@quikcommit/cli 10.0.0 → 11.1.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 +1477 -680
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -89,9 +89,14 @@ function slugifyFilename(path) {
89
89
  const noExt = basename.replace(/\.[^.]+$/, "");
90
90
  return noExt.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40);
91
91
  }
92
+ function pickBestFile(files) {
93
+ const codeFiles = files.filter((f) => !NON_CODE_PATTERNS.some((rx) => rx.test(f)));
94
+ return codeFiles[0] ?? files[0] ?? "";
95
+ }
92
96
  function deterministicBranchName(opts) {
93
97
  const files = opts.files ?? [];
94
- const haystack = `${opts.description ?? ""} ${files.join(" ")}`;
98
+ const codeFiles = files.filter((f) => !NON_CODE_PATTERNS.some((rx) => rx.test(f)));
99
+ const haystack = `${opts.description ?? ""} ${(codeFiles.length > 0 ? codeFiles : files).join(" ")}`;
95
100
  let type = "chore";
96
101
  for (const [rx, t] of TYPE_HINTS) {
97
102
  if (rx.test(haystack)) {
@@ -103,7 +108,7 @@ function deterministicBranchName(opts) {
103
108
  if (opts.description) {
104
109
  slug = opts.description.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").split("-").slice(0, 5).join("-").slice(0, 40);
105
110
  } else if (files.length > 0) {
106
- slug = slugifyFilename(files[0] ?? "");
111
+ slug = slugifyFilename(pickBestFile(files));
107
112
  } else {
108
113
  slug = "changes";
109
114
  }
@@ -117,7 +122,7 @@ function deterministicBranchName(opts) {
117
122
  }
118
123
  return { name, type, slug };
119
124
  }
120
- var BRANCH_NAME_RX, PROTECTED_BRANCH_RX, MAX_BRANCH_NAME_LENGTH, TYPE_HINTS;
125
+ var BRANCH_NAME_RX, PROTECTED_BRANCH_RX, MAX_BRANCH_NAME_LENGTH, TYPE_HINTS, NON_CODE_PATTERNS;
121
126
  var init_branch = __esm({
122
127
  "../shared/dist/branch.js"() {
123
128
  "use strict";
@@ -133,6 +138,21 @@ var init_branch = __esm({
133
138
  [/\bfix|bug|issue/i, "fix"],
134
139
  [/\bfeat|add|new\b/i, "feat"]
135
140
  ];
141
+ NON_CODE_PATTERNS = [
142
+ /^docs?\//i,
143
+ /^\.env/,
144
+ /\.md$/i,
145
+ /^readme/i,
146
+ /^changelog/i,
147
+ /^license/i,
148
+ /\.lock$/,
149
+ /\.ya?ml$/,
150
+ /\.json$/,
151
+ /\.toml$/,
152
+ /\/\.?config\b/i,
153
+ /^\.github\//,
154
+ /^\.vscode\//
155
+ ];
136
156
  }
137
157
  });
138
158
 
@@ -585,13 +605,13 @@ var require_identity = __commonJS({
585
605
  var require_visit = __commonJS({
586
606
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/visit.js"(exports2) {
587
607
  "use strict";
588
- var identity = require_identity();
608
+ var identity2 = require_identity();
589
609
  var BREAK = /* @__PURE__ */ Symbol("break visit");
590
610
  var SKIP = /* @__PURE__ */ Symbol("skip children");
591
611
  var REMOVE = /* @__PURE__ */ Symbol("remove node");
592
612
  function visit(node, visitor) {
593
613
  const visitor_ = initVisitor(visitor);
594
- if (identity.isDocument(node)) {
614
+ if (identity2.isDocument(node)) {
595
615
  const cd = visit_(null, node.contents, visitor_, Object.freeze([node]));
596
616
  if (cd === REMOVE)
597
617
  node.contents = null;
@@ -603,12 +623,12 @@ var require_visit = __commonJS({
603
623
  visit.REMOVE = REMOVE;
604
624
  function visit_(key, node, visitor, path) {
605
625
  const ctrl = callVisitor(key, node, visitor, path);
606
- if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
626
+ if (identity2.isNode(ctrl) || identity2.isPair(ctrl)) {
607
627
  replaceNode(key, path, ctrl);
608
628
  return visit_(key, ctrl, visitor, path);
609
629
  }
610
630
  if (typeof ctrl !== "symbol") {
611
- if (identity.isCollection(node)) {
631
+ if (identity2.isCollection(node)) {
612
632
  path = Object.freeze(path.concat(node));
613
633
  for (let i = 0; i < node.items.length; ++i) {
614
634
  const ci = visit_(i, node.items[i], visitor, path);
@@ -621,7 +641,7 @@ var require_visit = __commonJS({
621
641
  i -= 1;
622
642
  }
623
643
  }
624
- } else if (identity.isPair(node)) {
644
+ } else if (identity2.isPair(node)) {
625
645
  path = Object.freeze(path.concat(node));
626
646
  const ck = visit_("key", node.key, visitor, path);
627
647
  if (ck === BREAK)
@@ -639,7 +659,7 @@ var require_visit = __commonJS({
639
659
  }
640
660
  async function visitAsync(node, visitor) {
641
661
  const visitor_ = initVisitor(visitor);
642
- if (identity.isDocument(node)) {
662
+ if (identity2.isDocument(node)) {
643
663
  const cd = await visitAsync_(null, node.contents, visitor_, Object.freeze([node]));
644
664
  if (cd === REMOVE)
645
665
  node.contents = null;
@@ -651,12 +671,12 @@ var require_visit = __commonJS({
651
671
  visitAsync.REMOVE = REMOVE;
652
672
  async function visitAsync_(key, node, visitor, path) {
653
673
  const ctrl = await callVisitor(key, node, visitor, path);
654
- if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
674
+ if (identity2.isNode(ctrl) || identity2.isPair(ctrl)) {
655
675
  replaceNode(key, path, ctrl);
656
676
  return visitAsync_(key, ctrl, visitor, path);
657
677
  }
658
678
  if (typeof ctrl !== "symbol") {
659
- if (identity.isCollection(node)) {
679
+ if (identity2.isCollection(node)) {
660
680
  path = Object.freeze(path.concat(node));
661
681
  for (let i = 0; i < node.items.length; ++i) {
662
682
  const ci = await visitAsync_(i, node.items[i], visitor, path);
@@ -669,7 +689,7 @@ var require_visit = __commonJS({
669
689
  i -= 1;
670
690
  }
671
691
  }
672
- } else if (identity.isPair(node)) {
692
+ } else if (identity2.isPair(node)) {
673
693
  path = Object.freeze(path.concat(node));
674
694
  const ck = await visitAsync_("key", node.key, visitor, path);
675
695
  if (ck === BREAK)
@@ -706,31 +726,31 @@ var require_visit = __commonJS({
706
726
  function callVisitor(key, node, visitor, path) {
707
727
  if (typeof visitor === "function")
708
728
  return visitor(key, node, path);
709
- if (identity.isMap(node))
729
+ if (identity2.isMap(node))
710
730
  return visitor.Map?.(key, node, path);
711
- if (identity.isSeq(node))
731
+ if (identity2.isSeq(node))
712
732
  return visitor.Seq?.(key, node, path);
713
- if (identity.isPair(node))
733
+ if (identity2.isPair(node))
714
734
  return visitor.Pair?.(key, node, path);
715
- if (identity.isScalar(node))
735
+ if (identity2.isScalar(node))
716
736
  return visitor.Scalar?.(key, node, path);
717
- if (identity.isAlias(node))
737
+ if (identity2.isAlias(node))
718
738
  return visitor.Alias?.(key, node, path);
719
739
  return void 0;
720
740
  }
721
741
  function replaceNode(key, path, node) {
722
742
  const parent = path[path.length - 1];
723
- if (identity.isCollection(parent)) {
743
+ if (identity2.isCollection(parent)) {
724
744
  parent.items[key] = node;
725
- } else if (identity.isPair(parent)) {
745
+ } else if (identity2.isPair(parent)) {
726
746
  if (key === "key")
727
747
  parent.key = node;
728
748
  else
729
749
  parent.value = node;
730
- } else if (identity.isDocument(parent)) {
750
+ } else if (identity2.isDocument(parent)) {
731
751
  parent.contents = node;
732
752
  } else {
733
- const pt = identity.isAlias(parent) ? "alias" : "scalar";
753
+ const pt = identity2.isAlias(parent) ? "alias" : "scalar";
734
754
  throw new Error(`Cannot replace node with ${pt} parent`);
735
755
  }
736
756
  }
@@ -743,7 +763,7 @@ var require_visit = __commonJS({
743
763
  var require_directives = __commonJS({
744
764
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/doc/directives.js"(exports2) {
745
765
  "use strict";
746
- var identity = require_identity();
766
+ var identity2 = require_identity();
747
767
  var visit = require_visit();
748
768
  var escapeChars = {
749
769
  "!": "%21",
@@ -886,10 +906,10 @@ var require_directives = __commonJS({
886
906
  const lines = this.yaml.explicit ? [`%YAML ${this.yaml.version || "1.2"}`] : [];
887
907
  const tagEntries = Object.entries(this.tags);
888
908
  let tagNames;
889
- if (doc && tagEntries.length > 0 && identity.isNode(doc.contents)) {
909
+ if (doc && tagEntries.length > 0 && identity2.isNode(doc.contents)) {
890
910
  const tags = {};
891
911
  visit.visit(doc.contents, (_key, node) => {
892
- if (identity.isNode(node) && node.tag)
912
+ if (identity2.isNode(node) && node.tag)
893
913
  tags[node.tag] = true;
894
914
  });
895
915
  tagNames = Object.keys(tags);
@@ -914,7 +934,7 @@ var require_directives = __commonJS({
914
934
  var require_anchors = __commonJS({
915
935
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/doc/anchors.js"(exports2) {
916
936
  "use strict";
917
- var identity = require_identity();
937
+ var identity2 = require_identity();
918
938
  var visit = require_visit();
919
939
  function anchorIsValid(anchor) {
920
940
  if (/[\x00-\x19\s,[\]{}]/.test(anchor)) {
@@ -961,7 +981,7 @@ var require_anchors = __commonJS({
961
981
  setAnchors: () => {
962
982
  for (const source of aliasObjects) {
963
983
  const ref = sourceObjects.get(source);
964
- if (typeof ref === "object" && ref.anchor && (identity.isScalar(ref.node) || identity.isCollection(ref.node))) {
984
+ if (typeof ref === "object" && ref.anchor && (identity2.isScalar(ref.node) || identity2.isCollection(ref.node))) {
965
985
  ref.node.anchor = ref.anchor;
966
986
  } else {
967
987
  const error = new Error("Failed to resolve repeated object (this should not happen)");
@@ -1034,12 +1054,12 @@ var require_applyReviver = __commonJS({
1034
1054
  var require_toJS = __commonJS({
1035
1055
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/nodes/toJS.js"(exports2) {
1036
1056
  "use strict";
1037
- var identity = require_identity();
1057
+ var identity2 = require_identity();
1038
1058
  function toJS(value, arg, ctx) {
1039
1059
  if (Array.isArray(value))
1040
1060
  return value.map((v, i) => toJS(v, String(i), ctx));
1041
1061
  if (value && typeof value.toJSON === "function") {
1042
- if (!ctx || !identity.hasAnchor(value))
1062
+ if (!ctx || !identity2.hasAnchor(value))
1043
1063
  return value.toJSON(arg, ctx);
1044
1064
  const data = { aliasCount: 0, count: 1, res: void 0 };
1045
1065
  ctx.anchors.set(value, data);
@@ -1065,11 +1085,11 @@ var require_Node = __commonJS({
1065
1085
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/nodes/Node.js"(exports2) {
1066
1086
  "use strict";
1067
1087
  var applyReviver = require_applyReviver();
1068
- var identity = require_identity();
1088
+ var identity2 = require_identity();
1069
1089
  var toJS = require_toJS();
1070
1090
  var NodeBase = class {
1071
1091
  constructor(type) {
1072
- Object.defineProperty(this, identity.NODE_TYPE, { value: type });
1092
+ Object.defineProperty(this, identity2.NODE_TYPE, { value: type });
1073
1093
  }
1074
1094
  /** Create a copy of this node. */
1075
1095
  clone() {
@@ -1080,7 +1100,7 @@ var require_Node = __commonJS({
1080
1100
  }
1081
1101
  /** A plain JavaScript representation of this node. */
1082
1102
  toJS(doc, { mapAsMap, maxAliasCount, onAnchor, reviver } = {}) {
1083
- if (!identity.isDocument(doc))
1103
+ if (!identity2.isDocument(doc))
1084
1104
  throw new TypeError("A document argument is required");
1085
1105
  const ctx = {
1086
1106
  anchors: /* @__PURE__ */ new Map(),
@@ -1107,12 +1127,12 @@ var require_Alias = __commonJS({
1107
1127
  "use strict";
1108
1128
  var anchors = require_anchors();
1109
1129
  var visit = require_visit();
1110
- var identity = require_identity();
1130
+ var identity2 = require_identity();
1111
1131
  var Node = require_Node();
1112
1132
  var toJS = require_toJS();
1113
1133
  var Alias = class extends Node.NodeBase {
1114
1134
  constructor(source) {
1115
- super(identity.ALIAS);
1135
+ super(identity2.ALIAS);
1116
1136
  this.source = source;
1117
1137
  Object.defineProperty(this, "tag", {
1118
1138
  set() {
@@ -1134,7 +1154,7 @@ var require_Alias = __commonJS({
1134
1154
  nodes = [];
1135
1155
  visit.visit(doc, {
1136
1156
  Node: (_key, node) => {
1137
- if (identity.isAlias(node) || identity.hasAnchor(node))
1157
+ if (identity2.isAlias(node) || identity2.hasAnchor(node))
1138
1158
  nodes.push(node);
1139
1159
  }
1140
1160
  });
@@ -1194,11 +1214,11 @@ var require_Alias = __commonJS({
1194
1214
  }
1195
1215
  };
1196
1216
  function getAliasCount(doc, node, anchors2) {
1197
- if (identity.isAlias(node)) {
1217
+ if (identity2.isAlias(node)) {
1198
1218
  const source = node.resolve(doc);
1199
1219
  const anchor = anchors2 && source && anchors2.get(source);
1200
1220
  return anchor ? anchor.count * anchor.aliasCount : 0;
1201
- } else if (identity.isCollection(node)) {
1221
+ } else if (identity2.isCollection(node)) {
1202
1222
  let count = 0;
1203
1223
  for (const item of node.items) {
1204
1224
  const c = getAliasCount(doc, item, anchors2);
@@ -1206,7 +1226,7 @@ var require_Alias = __commonJS({
1206
1226
  count = c;
1207
1227
  }
1208
1228
  return count;
1209
- } else if (identity.isPair(node)) {
1229
+ } else if (identity2.isPair(node)) {
1210
1230
  const kc = getAliasCount(doc, node.key, anchors2);
1211
1231
  const vc = getAliasCount(doc, node.value, anchors2);
1212
1232
  return Math.max(kc, vc);
@@ -1221,13 +1241,13 @@ var require_Alias = __commonJS({
1221
1241
  var require_Scalar = __commonJS({
1222
1242
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/nodes/Scalar.js"(exports2) {
1223
1243
  "use strict";
1224
- var identity = require_identity();
1244
+ var identity2 = require_identity();
1225
1245
  var Node = require_Node();
1226
1246
  var toJS = require_toJS();
1227
1247
  var isScalarValue = (value) => !value || typeof value !== "function" && typeof value !== "object";
1228
1248
  var Scalar = class extends Node.NodeBase {
1229
1249
  constructor(value) {
1230
- super(identity.SCALAR);
1250
+ super(identity2.SCALAR);
1231
1251
  this.value = value;
1232
1252
  }
1233
1253
  toJSON(arg, ctx) {
@@ -1252,7 +1272,7 @@ var require_createNode = __commonJS({
1252
1272
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/doc/createNode.js"(exports2) {
1253
1273
  "use strict";
1254
1274
  var Alias = require_Alias();
1255
- var identity = require_identity();
1275
+ var identity2 = require_identity();
1256
1276
  var Scalar = require_Scalar();
1257
1277
  var defaultTagPrefix = "tag:yaml.org,2002:";
1258
1278
  function findTagObject(value, tagName, tags) {
@@ -1266,12 +1286,12 @@ var require_createNode = __commonJS({
1266
1286
  return tags.find((t) => t.identify?.(value) && !t.format);
1267
1287
  }
1268
1288
  function createNode(value, tagName, ctx) {
1269
- if (identity.isDocument(value))
1289
+ if (identity2.isDocument(value))
1270
1290
  value = value.contents;
1271
- if (identity.isNode(value))
1291
+ if (identity2.isNode(value))
1272
1292
  return value;
1273
- if (identity.isPair(value)) {
1274
- const map = ctx.schema[identity.MAP].createNode?.(ctx.schema, null, ctx);
1293
+ if (identity2.isPair(value)) {
1294
+ const map = ctx.schema[identity2.MAP].createNode?.(ctx.schema, null, ctx);
1275
1295
  map.items.push(value);
1276
1296
  return map;
1277
1297
  }
@@ -1303,7 +1323,7 @@ var require_createNode = __commonJS({
1303
1323
  ref.node = node2;
1304
1324
  return node2;
1305
1325
  }
1306
- tagObj = value instanceof Map ? schema[identity.MAP] : Symbol.iterator in Object(value) ? schema[identity.SEQ] : schema[identity.MAP];
1326
+ tagObj = value instanceof Map ? schema[identity2.MAP] : Symbol.iterator in Object(value) ? schema[identity2.SEQ] : schema[identity2.MAP];
1307
1327
  }
1308
1328
  if (onTagObj) {
1309
1329
  onTagObj(tagObj);
@@ -1327,7 +1347,7 @@ var require_Collection = __commonJS({
1327
1347
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/nodes/Collection.js"(exports2) {
1328
1348
  "use strict";
1329
1349
  var createNode = require_createNode();
1330
- var identity = require_identity();
1350
+ var identity2 = require_identity();
1331
1351
  var Node = require_Node();
1332
1352
  function collectionFromPath(schema, path, value) {
1333
1353
  let v = value;
@@ -1371,7 +1391,7 @@ var require_Collection = __commonJS({
1371
1391
  const copy = Object.create(Object.getPrototypeOf(this), Object.getOwnPropertyDescriptors(this));
1372
1392
  if (schema)
1373
1393
  copy.schema = schema;
1374
- copy.items = copy.items.map((it) => identity.isNode(it) || identity.isPair(it) ? it.clone(schema) : it);
1394
+ copy.items = copy.items.map((it) => identity2.isNode(it) || identity2.isPair(it) ? it.clone(schema) : it);
1375
1395
  if (this.range)
1376
1396
  copy.range = this.range.slice();
1377
1397
  return copy;
@@ -1387,7 +1407,7 @@ var require_Collection = __commonJS({
1387
1407
  else {
1388
1408
  const [key, ...rest] = path;
1389
1409
  const node = this.get(key, true);
1390
- if (identity.isCollection(node))
1410
+ if (identity2.isCollection(node))
1391
1411
  node.addIn(rest, value);
1392
1412
  else if (node === void 0 && this.schema)
1393
1413
  this.set(key, collectionFromPath(this.schema, rest, value));
@@ -1404,7 +1424,7 @@ var require_Collection = __commonJS({
1404
1424
  if (rest.length === 0)
1405
1425
  return this.delete(key);
1406
1426
  const node = this.get(key, true);
1407
- if (identity.isCollection(node))
1427
+ if (identity2.isCollection(node))
1408
1428
  return node.deleteIn(rest);
1409
1429
  else
1410
1430
  throw new Error(`Expected YAML collection at ${key}. Remaining path: ${rest}`);
@@ -1418,16 +1438,16 @@ var require_Collection = __commonJS({
1418
1438
  const [key, ...rest] = path;
1419
1439
  const node = this.get(key, true);
1420
1440
  if (rest.length === 0)
1421
- return !keepScalar && identity.isScalar(node) ? node.value : node;
1441
+ return !keepScalar && identity2.isScalar(node) ? node.value : node;
1422
1442
  else
1423
- return identity.isCollection(node) ? node.getIn(rest, keepScalar) : void 0;
1443
+ return identity2.isCollection(node) ? node.getIn(rest, keepScalar) : void 0;
1424
1444
  }
1425
1445
  hasAllNullValues(allowScalar) {
1426
1446
  return this.items.every((node) => {
1427
- if (!identity.isPair(node))
1447
+ if (!identity2.isPair(node))
1428
1448
  return false;
1429
1449
  const n = node.value;
1430
- return n == null || allowScalar && identity.isScalar(n) && n.value == null && !n.commentBefore && !n.comment && !n.tag;
1450
+ return n == null || allowScalar && identity2.isScalar(n) && n.value == null && !n.commentBefore && !n.comment && !n.tag;
1431
1451
  });
1432
1452
  }
1433
1453
  /**
@@ -1438,7 +1458,7 @@ var require_Collection = __commonJS({
1438
1458
  if (rest.length === 0)
1439
1459
  return this.has(key);
1440
1460
  const node = this.get(key, true);
1441
- return identity.isCollection(node) ? node.hasIn(rest) : false;
1461
+ return identity2.isCollection(node) ? node.hasIn(rest) : false;
1442
1462
  }
1443
1463
  /**
1444
1464
  * Sets a value in this collection. For `!!set`, `value` needs to be a
@@ -1450,7 +1470,7 @@ var require_Collection = __commonJS({
1450
1470
  this.set(key, value);
1451
1471
  } else {
1452
1472
  const node = this.get(key, true);
1453
- if (identity.isCollection(node))
1473
+ if (identity2.isCollection(node))
1454
1474
  node.setIn(rest, value);
1455
1475
  else if (node === void 0 && this.schema)
1456
1476
  this.set(key, collectionFromPath(this.schema, rest, value));
@@ -1906,7 +1926,7 @@ var require_stringify = __commonJS({
1906
1926
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/stringify/stringify.js"(exports2) {
1907
1927
  "use strict";
1908
1928
  var anchors = require_anchors();
1909
- var identity = require_identity();
1929
+ var identity2 = require_identity();
1910
1930
  var stringifyComment = require_stringifyComment();
1911
1931
  var stringifyString = require_stringifyString();
1912
1932
  function createStringifyContext(doc, options) {
@@ -1959,7 +1979,7 @@ var require_stringify = __commonJS({
1959
1979
  }
1960
1980
  let tagObj = void 0;
1961
1981
  let obj;
1962
- if (identity.isScalar(item)) {
1982
+ if (identity2.isScalar(item)) {
1963
1983
  obj = item.value;
1964
1984
  let match = tags.filter((t) => t.identify?.(obj));
1965
1985
  if (match.length > 1) {
@@ -1982,7 +2002,7 @@ var require_stringify = __commonJS({
1982
2002
  if (!doc.directives)
1983
2003
  return "";
1984
2004
  const props = [];
1985
- const anchor = (identity.isScalar(node) || identity.isCollection(node)) && node.anchor;
2005
+ const anchor = (identity2.isScalar(node) || identity2.isCollection(node)) && node.anchor;
1986
2006
  if (anchor && anchors.anchorIsValid(anchor)) {
1987
2007
  anchors$1.add(anchor);
1988
2008
  props.push(`&${anchor}`);
@@ -1993,9 +2013,9 @@ var require_stringify = __commonJS({
1993
2013
  return props.join(" ");
1994
2014
  }
1995
2015
  function stringify(item, ctx, onComment, onChompKeep) {
1996
- if (identity.isPair(item))
2016
+ if (identity2.isPair(item))
1997
2017
  return item.toString(ctx, onComment, onChompKeep);
1998
- if (identity.isAlias(item)) {
2018
+ if (identity2.isAlias(item)) {
1999
2019
  if (ctx.doc.directives)
2000
2020
  return item.toString(ctx);
2001
2021
  if (ctx.resolvedAliases?.has(item)) {
@@ -2009,15 +2029,15 @@ var require_stringify = __commonJS({
2009
2029
  }
2010
2030
  }
2011
2031
  let tagObj = void 0;
2012
- const node = identity.isNode(item) ? item : ctx.doc.createNode(item, { onTagObj: (o) => tagObj = o });
2032
+ const node = identity2.isNode(item) ? item : ctx.doc.createNode(item, { onTagObj: (o) => tagObj = o });
2013
2033
  tagObj ?? (tagObj = getTagObject(ctx.doc.schema.tags, node));
2014
2034
  const props = stringifyProps(node, tagObj, ctx);
2015
2035
  if (props.length > 0)
2016
2036
  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);
2037
+ 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
2038
  if (!props)
2019
2039
  return str;
2020
- return identity.isScalar(node) || str[0] === "{" || str[0] === "[" ? `${props} ${str}` : `${props}
2040
+ return identity2.isScalar(node) || str[0] === "{" || str[0] === "[" ? `${props} ${str}` : `${props}
2021
2041
  ${ctx.indent}${str}`;
2022
2042
  }
2023
2043
  exports2.createStringifyContext = createStringifyContext;
@@ -2029,23 +2049,23 @@ ${ctx.indent}${str}`;
2029
2049
  var require_stringifyPair = __commonJS({
2030
2050
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/stringify/stringifyPair.js"(exports2) {
2031
2051
  "use strict";
2032
- var identity = require_identity();
2052
+ var identity2 = require_identity();
2033
2053
  var Scalar = require_Scalar();
2034
2054
  var stringify = require_stringify();
2035
2055
  var stringifyComment = require_stringifyComment();
2036
2056
  function stringifyPair({ key, value }, ctx, onComment, onChompKeep) {
2037
2057
  const { allNullValues, doc, indent, indentStep, options: { commentString, indentSeq, simpleKeys } } = ctx;
2038
- let keyComment = identity.isNode(key) && key.comment || null;
2058
+ let keyComment = identity2.isNode(key) && key.comment || null;
2039
2059
  if (simpleKeys) {
2040
2060
  if (keyComment) {
2041
2061
  throw new Error("With simple keys, key nodes cannot have comments");
2042
2062
  }
2043
- if (identity.isCollection(key) || !identity.isNode(key) && typeof key === "object") {
2063
+ if (identity2.isCollection(key) || !identity2.isNode(key) && typeof key === "object") {
2044
2064
  const msg = "With simple keys, collection cannot be used as a key value";
2045
2065
  throw new Error(msg);
2046
2066
  }
2047
2067
  }
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"));
2068
+ 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
2069
  ctx = Object.assign({}, ctx, {
2050
2070
  allNullValues: false,
2051
2071
  implicitKey: !explicitKey && (simpleKeys || !allNullValues),
@@ -2086,7 +2106,7 @@ ${indent}:`;
2086
2106
  str += stringifyComment.lineComment(str, ctx.indent, commentString(keyComment));
2087
2107
  }
2088
2108
  let vsb, vcb, valueComment;
2089
- if (identity.isNode(value)) {
2109
+ if (identity2.isNode(value)) {
2090
2110
  vsb = !!value.spaceBefore;
2091
2111
  vcb = value.commentBefore;
2092
2112
  valueComment = value.comment;
@@ -2098,10 +2118,10 @@ ${indent}:`;
2098
2118
  value = doc.createNode(value);
2099
2119
  }
2100
2120
  ctx.implicitKey = false;
2101
- if (!explicitKey && !keyComment && identity.isScalar(value))
2121
+ if (!explicitKey && !keyComment && identity2.isScalar(value))
2102
2122
  ctx.indentAtStart = str.length + 1;
2103
2123
  chompKeep = false;
2104
- if (!indentSeq && indentStep.length >= 2 && !ctx.inFlow && !explicitKey && identity.isSeq(value) && !value.flow && !value.tag && !value.anchor) {
2124
+ if (!indentSeq && indentStep.length >= 2 && !ctx.inFlow && !explicitKey && identity2.isSeq(value) && !value.flow && !value.tag && !value.anchor) {
2105
2125
  ctx.indent = ctx.indent.substring(2);
2106
2126
  }
2107
2127
  let valueCommentDone = false;
@@ -2121,7 +2141,7 @@ ${stringifyComment.indentComment(cs, ctx.indent)}`;
2121
2141
  ws += `
2122
2142
  ${ctx.indent}`;
2123
2143
  }
2124
- } else if (!explicitKey && identity.isCollection(value)) {
2144
+ } else if (!explicitKey && identity2.isCollection(value)) {
2125
2145
  const vs0 = valueStr[0];
2126
2146
  const nl0 = valueStr.indexOf("\n");
2127
2147
  const hasNewline = nl0 !== -1;
@@ -2184,7 +2204,7 @@ var require_log = __commonJS({
2184
2204
  var require_merge = __commonJS({
2185
2205
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/schema/yaml-1.1/merge.js"(exports2) {
2186
2206
  "use strict";
2187
- var identity = require_identity();
2207
+ var identity2 = require_identity();
2188
2208
  var Scalar = require_Scalar();
2189
2209
  var MERGE_KEY = "<<";
2190
2210
  var merge = {
@@ -2197,10 +2217,10 @@ var require_merge = __commonJS({
2197
2217
  }),
2198
2218
  stringify: () => MERGE_KEY
2199
2219
  };
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);
2220
+ 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
2221
  function addMergeToJSMap(ctx, map, value) {
2202
2222
  const source = resolveAliasValue(ctx, value);
2203
- if (identity.isSeq(source))
2223
+ if (identity2.isSeq(source))
2204
2224
  for (const it of source.items)
2205
2225
  mergeValue(ctx, map, it);
2206
2226
  else if (Array.isArray(source))
@@ -2211,7 +2231,7 @@ var require_merge = __commonJS({
2211
2231
  }
2212
2232
  function mergeValue(ctx, map, value) {
2213
2233
  const source = resolveAliasValue(ctx, value);
2214
- if (!identity.isMap(source))
2234
+ if (!identity2.isMap(source))
2215
2235
  throw new Error("Merge sources must be maps or map aliases");
2216
2236
  const srcMap = source.toJSON(null, ctx, Map);
2217
2237
  for (const [key, value2] of srcMap) {
@@ -2232,7 +2252,7 @@ var require_merge = __commonJS({
2232
2252
  return map;
2233
2253
  }
2234
2254
  function resolveAliasValue(ctx, value) {
2235
- return ctx && identity.isAlias(value) ? value.resolve(ctx.doc, ctx) : value;
2255
+ return ctx && identity2.isAlias(value) ? value.resolve(ctx.doc, ctx) : value;
2236
2256
  }
2237
2257
  exports2.addMergeToJSMap = addMergeToJSMap;
2238
2258
  exports2.isMergeKey = isMergeKey;
@@ -2247,10 +2267,10 @@ var require_addPairToJSMap = __commonJS({
2247
2267
  var log = require_log();
2248
2268
  var merge = require_merge();
2249
2269
  var stringify = require_stringify();
2250
- var identity = require_identity();
2270
+ var identity2 = require_identity();
2251
2271
  var toJS = require_toJS();
2252
2272
  function addPairToJSMap(ctx, map, { key, value }) {
2253
- if (identity.isNode(key) && key.addToJSMap)
2273
+ if (identity2.isNode(key) && key.addToJSMap)
2254
2274
  key.addToJSMap(ctx, map, value);
2255
2275
  else if (merge.isMergeKey(ctx, key))
2256
2276
  merge.addMergeToJSMap(ctx, map, value);
@@ -2281,7 +2301,7 @@ var require_addPairToJSMap = __commonJS({
2281
2301
  return "";
2282
2302
  if (typeof jsKey !== "object")
2283
2303
  return String(jsKey);
2284
- if (identity.isNode(key) && ctx?.doc) {
2304
+ if (identity2.isNode(key) && ctx?.doc) {
2285
2305
  const strCtx = stringify.createStringifyContext(ctx.doc, {});
2286
2306
  strCtx.anchors = /* @__PURE__ */ new Set();
2287
2307
  for (const node of ctx.anchors.keys())
@@ -2311,7 +2331,7 @@ var require_Pair = __commonJS({
2311
2331
  var createNode = require_createNode();
2312
2332
  var stringifyPair = require_stringifyPair();
2313
2333
  var addPairToJSMap = require_addPairToJSMap();
2314
- var identity = require_identity();
2334
+ var identity2 = require_identity();
2315
2335
  function createPair(key, value, ctx) {
2316
2336
  const k = createNode.createNode(key, void 0, ctx);
2317
2337
  const v = createNode.createNode(value, void 0, ctx);
@@ -2319,15 +2339,15 @@ var require_Pair = __commonJS({
2319
2339
  }
2320
2340
  var Pair = class _Pair {
2321
2341
  constructor(key, value = null) {
2322
- Object.defineProperty(this, identity.NODE_TYPE, { value: identity.PAIR });
2342
+ Object.defineProperty(this, identity2.NODE_TYPE, { value: identity2.PAIR });
2323
2343
  this.key = key;
2324
2344
  this.value = value;
2325
2345
  }
2326
2346
  clone(schema) {
2327
2347
  let { key, value } = this;
2328
- if (identity.isNode(key))
2348
+ if (identity2.isNode(key))
2329
2349
  key = key.clone(schema);
2330
- if (identity.isNode(value))
2350
+ if (identity2.isNode(value))
2331
2351
  value = value.clone(schema);
2332
2352
  return new _Pair(key, value);
2333
2353
  }
@@ -2348,7 +2368,7 @@ var require_Pair = __commonJS({
2348
2368
  var require_stringifyCollection = __commonJS({
2349
2369
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/stringify/stringifyCollection.js"(exports2) {
2350
2370
  "use strict";
2351
- var identity = require_identity();
2371
+ var identity2 = require_identity();
2352
2372
  var stringify = require_stringify();
2353
2373
  var stringifyComment = require_stringifyComment();
2354
2374
  function stringifyCollection(collection, ctx, options) {
@@ -2364,14 +2384,14 @@ var require_stringifyCollection = __commonJS({
2364
2384
  for (let i = 0; i < items.length; ++i) {
2365
2385
  const item = items[i];
2366
2386
  let comment2 = null;
2367
- if (identity.isNode(item)) {
2387
+ if (identity2.isNode(item)) {
2368
2388
  if (!chompKeep && item.spaceBefore)
2369
2389
  lines.push("");
2370
2390
  addCommentBefore(ctx, lines, item.commentBefore, chompKeep);
2371
2391
  if (item.comment)
2372
2392
  comment2 = item.comment;
2373
- } else if (identity.isPair(item)) {
2374
- const ik = identity.isNode(item.key) ? item.key : null;
2393
+ } else if (identity2.isPair(item)) {
2394
+ const ik = identity2.isNode(item.key) ? item.key : null;
2375
2395
  if (ik) {
2376
2396
  if (!chompKeep && ik.spaceBefore)
2377
2397
  lines.push("");
@@ -2419,14 +2439,14 @@ ${indent}${line}` : "\n";
2419
2439
  for (let i = 0; i < items.length; ++i) {
2420
2440
  const item = items[i];
2421
2441
  let comment = null;
2422
- if (identity.isNode(item)) {
2442
+ if (identity2.isNode(item)) {
2423
2443
  if (item.spaceBefore)
2424
2444
  lines.push("");
2425
2445
  addCommentBefore(ctx, lines, item.commentBefore, false);
2426
2446
  if (item.comment)
2427
2447
  comment = item.comment;
2428
- } else if (identity.isPair(item)) {
2429
- const ik = identity.isNode(item.key) ? item.key : null;
2448
+ } else if (identity2.isPair(item)) {
2449
+ const ik = identity2.isNode(item.key) ? item.key : null;
2430
2450
  if (ik) {
2431
2451
  if (ik.spaceBefore)
2432
2452
  lines.push("");
@@ -2434,7 +2454,7 @@ ${indent}${line}` : "\n";
2434
2454
  if (ik.comment)
2435
2455
  reqNewline = true;
2436
2456
  }
2437
- const iv = identity.isNode(item.value) ? item.value : null;
2457
+ const iv = identity2.isNode(item.value) ? item.value : null;
2438
2458
  if (iv) {
2439
2459
  if (iv.comment)
2440
2460
  comment = iv.comment;
@@ -2502,16 +2522,16 @@ var require_YAMLMap = __commonJS({
2502
2522
  var stringifyCollection = require_stringifyCollection();
2503
2523
  var addPairToJSMap = require_addPairToJSMap();
2504
2524
  var Collection = require_Collection();
2505
- var identity = require_identity();
2525
+ var identity2 = require_identity();
2506
2526
  var Pair = require_Pair();
2507
2527
  var Scalar = require_Scalar();
2508
2528
  function findPair(items, key) {
2509
- const k = identity.isScalar(key) ? key.value : key;
2529
+ const k = identity2.isScalar(key) ? key.value : key;
2510
2530
  for (const it of items) {
2511
- if (identity.isPair(it)) {
2531
+ if (identity2.isPair(it)) {
2512
2532
  if (it.key === key || it.key === k)
2513
2533
  return it;
2514
- if (identity.isScalar(it.key) && it.key.value === k)
2534
+ if (identity2.isScalar(it.key) && it.key.value === k)
2515
2535
  return it;
2516
2536
  }
2517
2537
  }
@@ -2522,7 +2542,7 @@ var require_YAMLMap = __commonJS({
2522
2542
  return "tag:yaml.org,2002:map";
2523
2543
  }
2524
2544
  constructor(schema) {
2525
- super(identity.MAP, schema);
2545
+ super(identity2.MAP, schema);
2526
2546
  this.items = [];
2527
2547
  }
2528
2548
  /**
@@ -2560,7 +2580,7 @@ var require_YAMLMap = __commonJS({
2560
2580
  */
2561
2581
  add(pair, overwrite) {
2562
2582
  let _pair;
2563
- if (identity.isPair(pair))
2583
+ if (identity2.isPair(pair))
2564
2584
  _pair = pair;
2565
2585
  else if (!pair || typeof pair !== "object" || !("key" in pair)) {
2566
2586
  _pair = new Pair.Pair(pair, pair?.value);
@@ -2571,7 +2591,7 @@ var require_YAMLMap = __commonJS({
2571
2591
  if (prev) {
2572
2592
  if (!overwrite)
2573
2593
  throw new Error(`Key ${_pair.key} already set`);
2574
- if (identity.isScalar(prev.value) && Scalar.isScalarValue(_pair.value))
2594
+ if (identity2.isScalar(prev.value) && Scalar.isScalarValue(_pair.value))
2575
2595
  prev.value.value = _pair.value;
2576
2596
  else
2577
2597
  prev.value = _pair.value;
@@ -2595,7 +2615,7 @@ var require_YAMLMap = __commonJS({
2595
2615
  get(key, keepScalar) {
2596
2616
  const it = findPair(this.items, key);
2597
2617
  const node = it?.value;
2598
- return (!keepScalar && identity.isScalar(node) ? node.value : node) ?? void 0;
2618
+ return (!keepScalar && identity2.isScalar(node) ? node.value : node) ?? void 0;
2599
2619
  }
2600
2620
  has(key) {
2601
2621
  return !!findPair(this.items, key);
@@ -2620,7 +2640,7 @@ var require_YAMLMap = __commonJS({
2620
2640
  if (!ctx)
2621
2641
  return JSON.stringify(this);
2622
2642
  for (const item of this.items) {
2623
- if (!identity.isPair(item))
2643
+ if (!identity2.isPair(item))
2624
2644
  throw new Error(`Map items must all be pairs; found ${JSON.stringify(item)} instead`);
2625
2645
  }
2626
2646
  if (!ctx.allNullValues && this.hasAllNullValues(false))
@@ -2643,7 +2663,7 @@ var require_YAMLMap = __commonJS({
2643
2663
  var require_map = __commonJS({
2644
2664
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/schema/common/map.js"(exports2) {
2645
2665
  "use strict";
2646
- var identity = require_identity();
2666
+ var identity2 = require_identity();
2647
2667
  var YAMLMap = require_YAMLMap();
2648
2668
  var map = {
2649
2669
  collection: "map",
@@ -2651,7 +2671,7 @@ var require_map = __commonJS({
2651
2671
  nodeClass: YAMLMap.YAMLMap,
2652
2672
  tag: "tag:yaml.org,2002:map",
2653
2673
  resolve(map2, onError) {
2654
- if (!identity.isMap(map2))
2674
+ if (!identity2.isMap(map2))
2655
2675
  onError("Expected a mapping for this tag");
2656
2676
  return map2;
2657
2677
  },
@@ -2668,7 +2688,7 @@ var require_YAMLSeq = __commonJS({
2668
2688
  var createNode = require_createNode();
2669
2689
  var stringifyCollection = require_stringifyCollection();
2670
2690
  var Collection = require_Collection();
2671
- var identity = require_identity();
2691
+ var identity2 = require_identity();
2672
2692
  var Scalar = require_Scalar();
2673
2693
  var toJS = require_toJS();
2674
2694
  var YAMLSeq = class extends Collection.Collection {
@@ -2676,7 +2696,7 @@ var require_YAMLSeq = __commonJS({
2676
2696
  return "tag:yaml.org,2002:seq";
2677
2697
  }
2678
2698
  constructor(schema) {
2679
- super(identity.SEQ, schema);
2699
+ super(identity2.SEQ, schema);
2680
2700
  this.items = [];
2681
2701
  }
2682
2702
  add(value) {
@@ -2702,7 +2722,7 @@ var require_YAMLSeq = __commonJS({
2702
2722
  if (typeof idx !== "number")
2703
2723
  return void 0;
2704
2724
  const it = this.items[idx];
2705
- return !keepScalar && identity.isScalar(it) ? it.value : it;
2725
+ return !keepScalar && identity2.isScalar(it) ? it.value : it;
2706
2726
  }
2707
2727
  /**
2708
2728
  * Checks if the collection includes a value with the key `key`.
@@ -2726,7 +2746,7 @@ var require_YAMLSeq = __commonJS({
2726
2746
  if (typeof idx !== "number")
2727
2747
  throw new Error(`Expected a valid index, not ${key}.`);
2728
2748
  const prev = this.items[idx];
2729
- if (identity.isScalar(prev) && Scalar.isScalarValue(value))
2749
+ if (identity2.isScalar(prev) && Scalar.isScalarValue(value))
2730
2750
  prev.value = value;
2731
2751
  else
2732
2752
  this.items[idx] = value;
@@ -2768,7 +2788,7 @@ var require_YAMLSeq = __commonJS({
2768
2788
  }
2769
2789
  };
2770
2790
  function asItemIndex(key) {
2771
- let idx = identity.isScalar(key) ? key.value : key;
2791
+ let idx = identity2.isScalar(key) ? key.value : key;
2772
2792
  if (idx && typeof idx === "string")
2773
2793
  idx = Number(idx);
2774
2794
  return typeof idx === "number" && Number.isInteger(idx) && idx >= 0 ? idx : null;
@@ -2781,7 +2801,7 @@ var require_YAMLSeq = __commonJS({
2781
2801
  var require_seq = __commonJS({
2782
2802
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/schema/common/seq.js"(exports2) {
2783
2803
  "use strict";
2784
- var identity = require_identity();
2804
+ var identity2 = require_identity();
2785
2805
  var YAMLSeq = require_YAMLSeq();
2786
2806
  var seq = {
2787
2807
  collection: "seq",
@@ -2789,7 +2809,7 @@ var require_seq = __commonJS({
2789
2809
  nodeClass: YAMLSeq.YAMLSeq,
2790
2810
  tag: "tag:yaml.org,2002:seq",
2791
2811
  resolve(seq2, onError) {
2792
- if (!identity.isSeq(seq2))
2812
+ if (!identity2.isSeq(seq2))
2793
2813
  onError("Expected a sequence for this tag");
2794
2814
  return seq2;
2795
2815
  },
@@ -3143,17 +3163,17 @@ var require_binary = __commonJS({
3143
3163
  var require_pairs = __commonJS({
3144
3164
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/schema/yaml-1.1/pairs.js"(exports2) {
3145
3165
  "use strict";
3146
- var identity = require_identity();
3166
+ var identity2 = require_identity();
3147
3167
  var Pair = require_Pair();
3148
3168
  var Scalar = require_Scalar();
3149
3169
  var YAMLSeq = require_YAMLSeq();
3150
3170
  function resolvePairs(seq, onError) {
3151
- if (identity.isSeq(seq)) {
3171
+ if (identity2.isSeq(seq)) {
3152
3172
  for (let i = 0; i < seq.items.length; ++i) {
3153
3173
  let item = seq.items[i];
3154
- if (identity.isPair(item))
3174
+ if (identity2.isPair(item))
3155
3175
  continue;
3156
- else if (identity.isMap(item)) {
3176
+ else if (identity2.isMap(item)) {
3157
3177
  if (item.items.length > 1)
3158
3178
  onError("Each pair must have its own sequence indicator");
3159
3179
  const pair = item.items[0] || new Pair.Pair(new Scalar.Scalar(null));
@@ -3167,7 +3187,7 @@ ${cn.comment}` : item.comment;
3167
3187
  }
3168
3188
  item = pair;
3169
3189
  }
3170
- seq.items[i] = identity.isPair(item) ? item : new Pair.Pair(item);
3190
+ seq.items[i] = identity2.isPair(item) ? item : new Pair.Pair(item);
3171
3191
  }
3172
3192
  } else
3173
3193
  onError("Expected a sequence for this tag");
@@ -3221,7 +3241,7 @@ ${cn.comment}` : item.comment;
3221
3241
  var require_omap = __commonJS({
3222
3242
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/schema/yaml-1.1/omap.js"(exports2) {
3223
3243
  "use strict";
3224
- var identity = require_identity();
3244
+ var identity2 = require_identity();
3225
3245
  var toJS = require_toJS();
3226
3246
  var YAMLMap = require_YAMLMap();
3227
3247
  var YAMLSeq = require_YAMLSeq();
@@ -3248,7 +3268,7 @@ var require_omap = __commonJS({
3248
3268
  ctx.onCreate(map);
3249
3269
  for (const pair of this.items) {
3250
3270
  let key, value;
3251
- if (identity.isPair(pair)) {
3271
+ if (identity2.isPair(pair)) {
3252
3272
  key = toJS.toJS(pair.key, "", ctx);
3253
3273
  value = toJS.toJS(pair.value, key, ctx);
3254
3274
  } else {
@@ -3278,7 +3298,7 @@ var require_omap = __commonJS({
3278
3298
  const pairs$1 = pairs.resolvePairs(seq, onError);
3279
3299
  const seenKeys = [];
3280
3300
  for (const { key } of pairs$1.items) {
3281
- if (identity.isScalar(key)) {
3301
+ if (identity2.isScalar(key)) {
3282
3302
  if (seenKeys.includes(key.value)) {
3283
3303
  onError(`Ordered maps must not include duplicate keys: ${key.value}`);
3284
3304
  } else {
@@ -3459,7 +3479,7 @@ var require_int2 = __commonJS({
3459
3479
  var require_set = __commonJS({
3460
3480
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/schema/yaml-1.1/set.js"(exports2) {
3461
3481
  "use strict";
3462
- var identity = require_identity();
3482
+ var identity2 = require_identity();
3463
3483
  var Pair = require_Pair();
3464
3484
  var YAMLMap = require_YAMLMap();
3465
3485
  var YAMLSet = class _YAMLSet extends YAMLMap.YAMLMap {
@@ -3469,7 +3489,7 @@ var require_set = __commonJS({
3469
3489
  }
3470
3490
  add(key) {
3471
3491
  let pair;
3472
- if (identity.isPair(key))
3492
+ if (identity2.isPair(key))
3473
3493
  pair = key;
3474
3494
  else if (key && typeof key === "object" && "key" in key && "value" in key && key.value === null)
3475
3495
  pair = new Pair.Pair(key.key, null);
@@ -3485,7 +3505,7 @@ var require_set = __commonJS({
3485
3505
  */
3486
3506
  get(key, keepPair) {
3487
3507
  const pair = YAMLMap.findPair(this.items, key);
3488
- return !keepPair && identity.isPair(pair) ? identity.isScalar(pair.key) ? pair.key.value : pair.key : pair;
3508
+ return !keepPair && identity2.isPair(pair) ? identity2.isScalar(pair.key) ? pair.key.value : pair.key : pair;
3489
3509
  }
3490
3510
  set(key, value) {
3491
3511
  if (typeof value !== "boolean")
@@ -3529,7 +3549,7 @@ var require_set = __commonJS({
3529
3549
  tag: "tag:yaml.org,2002:set",
3530
3550
  createNode: (schema, iterable, ctx) => YAMLSet.from(schema, iterable, ctx),
3531
3551
  resolve(map, onError) {
3532
- if (identity.isMap(map)) {
3552
+ if (identity2.isMap(map)) {
3533
3553
  if (map.hasAllNullValues(true))
3534
3554
  return Object.assign(new YAMLSet(), map);
3535
3555
  else
@@ -3774,7 +3794,7 @@ var require_tags = __commonJS({
3774
3794
  var require_Schema = __commonJS({
3775
3795
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/schema/Schema.js"(exports2) {
3776
3796
  "use strict";
3777
- var identity = require_identity();
3797
+ var identity2 = require_identity();
3778
3798
  var map = require_map();
3779
3799
  var seq = require_seq();
3780
3800
  var string = require_string();
@@ -3787,9 +3807,9 @@ var require_Schema = __commonJS({
3787
3807
  this.knownTags = resolveKnownTags ? tags.coreKnownTags : {};
3788
3808
  this.tags = tags.getTags(customTags, this.name, merge);
3789
3809
  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 });
3810
+ Object.defineProperty(this, identity2.MAP, { value: map.map });
3811
+ Object.defineProperty(this, identity2.SCALAR, { value: string.string });
3812
+ Object.defineProperty(this, identity2.SEQ, { value: seq.seq });
3793
3813
  this.sortMapEntries = typeof sortMapEntries === "function" ? sortMapEntries : sortMapEntries === true ? sortMapEntriesByKey : null;
3794
3814
  }
3795
3815
  clone() {
@@ -3806,7 +3826,7 @@ var require_Schema = __commonJS({
3806
3826
  var require_stringifyDocument = __commonJS({
3807
3827
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/stringify/stringifyDocument.js"(exports2) {
3808
3828
  "use strict";
3809
- var identity = require_identity();
3829
+ var identity2 = require_identity();
3810
3830
  var stringify = require_stringify();
3811
3831
  var stringifyComment = require_stringifyComment();
3812
3832
  function stringifyDocument(doc, options) {
@@ -3833,7 +3853,7 @@ var require_stringifyDocument = __commonJS({
3833
3853
  let chompKeep = false;
3834
3854
  let contentComment = null;
3835
3855
  if (doc.contents) {
3836
- if (identity.isNode(doc.contents)) {
3856
+ if (identity2.isNode(doc.contents)) {
3837
3857
  if (doc.contents.spaceBefore && hasDirectives)
3838
3858
  lines.push("");
3839
3859
  if (doc.contents.commentBefore) {
@@ -3888,7 +3908,7 @@ var require_Document = __commonJS({
3888
3908
  "use strict";
3889
3909
  var Alias = require_Alias();
3890
3910
  var Collection = require_Collection();
3891
- var identity = require_identity();
3911
+ var identity2 = require_identity();
3892
3912
  var Pair = require_Pair();
3893
3913
  var toJS = require_toJS();
3894
3914
  var Schema = require_Schema();
@@ -3903,7 +3923,7 @@ var require_Document = __commonJS({
3903
3923
  this.comment = null;
3904
3924
  this.errors = [];
3905
3925
  this.warnings = [];
3906
- Object.defineProperty(this, identity.NODE_TYPE, { value: identity.DOC });
3926
+ Object.defineProperty(this, identity2.NODE_TYPE, { value: identity2.DOC });
3907
3927
  let _replacer = null;
3908
3928
  if (typeof replacer === "function" || Array.isArray(replacer)) {
3909
3929
  _replacer = replacer;
@@ -3939,7 +3959,7 @@ var require_Document = __commonJS({
3939
3959
  */
3940
3960
  clone() {
3941
3961
  const copy = Object.create(_Document.prototype, {
3942
- [identity.NODE_TYPE]: { value: identity.DOC }
3962
+ [identity2.NODE_TYPE]: { value: identity2.DOC }
3943
3963
  });
3944
3964
  copy.commentBefore = this.commentBefore;
3945
3965
  copy.comment = this.comment;
@@ -3949,7 +3969,7 @@ var require_Document = __commonJS({
3949
3969
  if (this.directives)
3950
3970
  copy.directives = this.directives.clone();
3951
3971
  copy.schema = this.schema.clone();
3952
- copy.contents = identity.isNode(this.contents) ? this.contents.clone(copy.schema) : this.contents;
3972
+ copy.contents = identity2.isNode(this.contents) ? this.contents.clone(copy.schema) : this.contents;
3953
3973
  if (this.range)
3954
3974
  copy.range = this.range.slice();
3955
3975
  return copy;
@@ -4012,7 +4032,7 @@ var require_Document = __commonJS({
4012
4032
  sourceObjects
4013
4033
  };
4014
4034
  const node = createNode.createNode(value, tag, ctx);
4015
- if (flow && identity.isCollection(node))
4035
+ if (flow && identity2.isCollection(node))
4016
4036
  node.flow = true;
4017
4037
  setAnchors();
4018
4038
  return node;
@@ -4052,7 +4072,7 @@ var require_Document = __commonJS({
4052
4072
  * `true` (collections are always returned intact).
4053
4073
  */
4054
4074
  get(key, keepScalar) {
4055
- return identity.isCollection(this.contents) ? this.contents.get(key, keepScalar) : void 0;
4075
+ return identity2.isCollection(this.contents) ? this.contents.get(key, keepScalar) : void 0;
4056
4076
  }
4057
4077
  /**
4058
4078
  * Returns item at `path`, or `undefined` if not found. By default unwraps
@@ -4061,14 +4081,14 @@ var require_Document = __commonJS({
4061
4081
  */
4062
4082
  getIn(path, keepScalar) {
4063
4083
  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;
4084
+ return !keepScalar && identity2.isScalar(this.contents) ? this.contents.value : this.contents;
4085
+ return identity2.isCollection(this.contents) ? this.contents.getIn(path, keepScalar) : void 0;
4066
4086
  }
4067
4087
  /**
4068
4088
  * Checks if the document includes a value with the key `key`.
4069
4089
  */
4070
4090
  has(key) {
4071
- return identity.isCollection(this.contents) ? this.contents.has(key) : false;
4091
+ return identity2.isCollection(this.contents) ? this.contents.has(key) : false;
4072
4092
  }
4073
4093
  /**
4074
4094
  * Checks if the document includes a value at `path`.
@@ -4076,7 +4096,7 @@ var require_Document = __commonJS({
4076
4096
  hasIn(path) {
4077
4097
  if (Collection.isEmptyPath(path))
4078
4098
  return this.contents !== void 0;
4079
- return identity.isCollection(this.contents) ? this.contents.hasIn(path) : false;
4099
+ return identity2.isCollection(this.contents) ? this.contents.hasIn(path) : false;
4080
4100
  }
4081
4101
  /**
4082
4102
  * Sets a value in this document. For `!!set`, `value` needs to be a
@@ -4183,7 +4203,7 @@ var require_Document = __commonJS({
4183
4203
  }
4184
4204
  };
4185
4205
  function assertCollection(contents) {
4186
- if (identity.isCollection(contents))
4206
+ if (identity2.isCollection(contents))
4187
4207
  return true;
4188
4208
  throw new Error("Expected a YAML collection as document contents");
4189
4209
  }
@@ -4454,12 +4474,12 @@ var require_util_flow_indent_check = __commonJS({
4454
4474
  var require_util_map_includes = __commonJS({
4455
4475
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/compose/util-map-includes.js"(exports2) {
4456
4476
  "use strict";
4457
- var identity = require_identity();
4477
+ var identity2 = require_identity();
4458
4478
  function mapIncludes(ctx, items, search) {
4459
4479
  const { uniqueKeys } = ctx.options;
4460
4480
  if (uniqueKeys === false)
4461
4481
  return false;
4462
- const isEqual = typeof uniqueKeys === "function" ? uniqueKeys : (a, b) => a === b || identity.isScalar(a) && identity.isScalar(b) && a.value === b.value;
4482
+ const isEqual = typeof uniqueKeys === "function" ? uniqueKeys : (a, b) => a === b || identity2.isScalar(a) && identity2.isScalar(b) && a.value === b.value;
4463
4483
  return items.some((pair) => isEqual(pair.key, search));
4464
4484
  }
4465
4485
  exports2.mapIncludes = mapIncludes;
@@ -4672,7 +4692,7 @@ var require_resolve_end = __commonJS({
4672
4692
  var require_resolve_flow_collection = __commonJS({
4673
4693
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/compose/resolve-flow-collection.js"(exports2) {
4674
4694
  "use strict";
4675
- var identity = require_identity();
4695
+ var identity2 = require_identity();
4676
4696
  var Pair = require_Pair();
4677
4697
  var YAMLMap = require_YAMLMap();
4678
4698
  var YAMLSeq = require_YAMLSeq();
@@ -4751,7 +4771,7 @@ var require_resolve_flow_collection = __commonJS({
4751
4771
  }
4752
4772
  if (prevItemComment) {
4753
4773
  let prev = coll.items[coll.items.length - 1];
4754
- if (identity.isPair(prev))
4774
+ if (identity2.isPair(prev))
4755
4775
  prev = prev.value ?? prev.key;
4756
4776
  if (prev.comment)
4757
4777
  prev.comment += "\n" + prevItemComment;
@@ -4866,7 +4886,7 @@ var require_resolve_flow_collection = __commonJS({
4866
4886
  var require_compose_collection = __commonJS({
4867
4887
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/compose/compose-collection.js"(exports2) {
4868
4888
  "use strict";
4869
- var identity = require_identity();
4889
+ var identity2 = require_identity();
4870
4890
  var Scalar = require_Scalar();
4871
4891
  var YAMLMap = require_YAMLMap();
4872
4892
  var YAMLSeq = require_YAMLSeq();
@@ -4916,7 +4936,7 @@ var require_compose_collection = __commonJS({
4916
4936
  }
4917
4937
  const coll = resolveCollection(CN, ctx, token, onError, tagName, tag);
4918
4938
  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);
4939
+ const node = identity2.isNode(res) ? res : new Scalar.Scalar(res);
4920
4940
  node.range = coll.range;
4921
4941
  node.tag = tagName;
4922
4942
  if (tag?.format)
@@ -5334,7 +5354,7 @@ var require_resolve_flow_scalar = __commonJS({
5334
5354
  var require_compose_scalar = __commonJS({
5335
5355
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/compose/compose-scalar.js"(exports2) {
5336
5356
  "use strict";
5337
- var identity = require_identity();
5357
+ var identity2 = require_identity();
5338
5358
  var Scalar = require_Scalar();
5339
5359
  var resolveBlockScalar = require_resolve_block_scalar();
5340
5360
  var resolveFlowScalar = require_resolve_flow_scalar();
@@ -5343,17 +5363,17 @@ var require_compose_scalar = __commonJS({
5343
5363
  const tagName = tagToken ? ctx.directives.tagName(tagToken.source, (msg) => onError(tagToken, "TAG_RESOLVE_FAILED", msg)) : null;
5344
5364
  let tag;
5345
5365
  if (ctx.options.stringKeys && ctx.atKey) {
5346
- tag = ctx.schema[identity.SCALAR];
5366
+ tag = ctx.schema[identity2.SCALAR];
5347
5367
  } else if (tagName)
5348
5368
  tag = findScalarTagByName(ctx.schema, value, tagName, tagToken, onError);
5349
5369
  else if (token.type === "scalar")
5350
5370
  tag = findScalarTagByTest(ctx, value, token, onError);
5351
5371
  else
5352
- tag = ctx.schema[identity.SCALAR];
5372
+ tag = ctx.schema[identity2.SCALAR];
5353
5373
  let scalar;
5354
5374
  try {
5355
5375
  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);
5376
+ scalar = identity2.isScalar(res) ? res : new Scalar.Scalar(res);
5357
5377
  } catch (error) {
5358
5378
  const msg = error instanceof Error ? error.message : String(error);
5359
5379
  onError(tagToken ?? token, "TAG_RESOLVE_FAILED", msg);
@@ -5373,7 +5393,7 @@ var require_compose_scalar = __commonJS({
5373
5393
  }
5374
5394
  function findScalarTagByName(schema, value, tagName, tagToken, onError) {
5375
5395
  if (tagName === "!")
5376
- return schema[identity.SCALAR];
5396
+ return schema[identity2.SCALAR];
5377
5397
  const matchWithTest = [];
5378
5398
  for (const tag of schema.tags) {
5379
5399
  if (!tag.collection && tag.tag === tagName) {
@@ -5392,12 +5412,12 @@ var require_compose_scalar = __commonJS({
5392
5412
  return kt;
5393
5413
  }
5394
5414
  onError(tagToken, "TAG_RESOLVE_FAILED", `Unresolved tag: ${tagName}`, tagName !== "tag:yaml.org,2002:str");
5395
- return schema[identity.SCALAR];
5415
+ return schema[identity2.SCALAR];
5396
5416
  }
5397
5417
  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];
5418
+ const tag = schema.tags.find((tag2) => (tag2.default === true || atKey && tag2.default === "key") && tag2.test?.test(value)) || schema[identity2.SCALAR];
5399
5419
  if (schema.compat) {
5400
- const compat = schema.compat.find((tag2) => tag2.default && tag2.test?.test(value)) ?? schema[identity.SCALAR];
5420
+ const compat = schema.compat.find((tag2) => tag2.default && tag2.test?.test(value)) ?? schema[identity2.SCALAR];
5401
5421
  if (tag.tag !== compat.tag) {
5402
5422
  const ts = directives.tagString(tag.tag);
5403
5423
  const cs = directives.tagString(compat.tag);
@@ -5446,7 +5466,7 @@ var require_compose_node = __commonJS({
5446
5466
  "../../node_modules/.pnpm/yaml@2.8.4/node_modules/yaml/dist/compose/compose-node.js"(exports2) {
5447
5467
  "use strict";
5448
5468
  var Alias = require_Alias();
5449
- var identity = require_identity();
5469
+ var identity2 = require_identity();
5450
5470
  var composeCollection = require_compose_collection();
5451
5471
  var composeScalar = require_compose_scalar();
5452
5472
  var resolveEnd = require_resolve_end();
@@ -5492,7 +5512,7 @@ var require_compose_node = __commonJS({
5492
5512
  node ?? (node = composeEmptyNode(ctx, token.offset, void 0, null, props, onError));
5493
5513
  if (anchor && node.anchor === "")
5494
5514
  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")) {
5515
+ if (atKey && ctx.options.stringKeys && (!identity2.isScalar(node) || typeof node.value !== "string" || node.tag && node.tag !== "tag:yaml.org,2002:str")) {
5496
5516
  const msg = "With stringKeys, all keys must be strings";
5497
5517
  onError(tag ?? token, "NON_STRING_KEY", msg);
5498
5518
  }
@@ -5598,7 +5618,7 @@ var require_composer = __commonJS({
5598
5618
  var directives = require_directives();
5599
5619
  var Document = require_Document();
5600
5620
  var errors = require_errors();
5601
- var identity = require_identity();
5621
+ var identity2 = require_identity();
5602
5622
  var composeDoc = require_compose_doc();
5603
5623
  var resolveEnd = require_resolve_end();
5604
5624
  function getErrorPos(src) {
@@ -5660,9 +5680,9 @@ var require_composer = __commonJS({
5660
5680
  ${comment}` : comment;
5661
5681
  } else if (afterEmptyLine || doc.directives.docStart || !dc) {
5662
5682
  doc.commentBefore = comment;
5663
- } else if (identity.isCollection(dc) && !dc.flow && dc.items.length > 0) {
5683
+ } else if (identity2.isCollection(dc) && !dc.flow && dc.items.length > 0) {
5664
5684
  let it = dc.items[0];
5665
- if (identity.isPair(it))
5685
+ if (identity2.isPair(it))
5666
5686
  it = it.key;
5667
5687
  const cb = it.commentBefore;
5668
5688
  it.commentBefore = cb ? `${comment}
@@ -7691,7 +7711,7 @@ var require_public_api = __commonJS({
7691
7711
  var Document = require_Document();
7692
7712
  var errors = require_errors();
7693
7713
  var log = require_log();
7694
- var identity = require_identity();
7714
+ var identity2 = require_identity();
7695
7715
  var lineCounter = require_line_counter();
7696
7716
  var parser = require_parser();
7697
7717
  function parseOptions(options) {
@@ -7769,7 +7789,7 @@ var require_public_api = __commonJS({
7769
7789
  if (!keepUndefined)
7770
7790
  return void 0;
7771
7791
  }
7772
- if (identity.isDocument(value) && !_replacer)
7792
+ if (identity2.isDocument(value) && !_replacer)
7773
7793
  return value.toString(options);
7774
7794
  return new Document.Document(value, _replacer, options).toString(options);
7775
7795
  }
@@ -7789,7 +7809,7 @@ var require_dist = __commonJS({
7789
7809
  var Schema = require_Schema();
7790
7810
  var errors = require_errors();
7791
7811
  var Alias = require_Alias();
7792
- var identity = require_identity();
7812
+ var identity2 = require_identity();
7793
7813
  var Pair = require_Pair();
7794
7814
  var Scalar = require_Scalar();
7795
7815
  var YAMLMap = require_YAMLMap();
@@ -7807,14 +7827,14 @@ var require_dist = __commonJS({
7807
7827
  exports2.YAMLParseError = errors.YAMLParseError;
7808
7828
  exports2.YAMLWarning = errors.YAMLWarning;
7809
7829
  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;
7830
+ exports2.isAlias = identity2.isAlias;
7831
+ exports2.isCollection = identity2.isCollection;
7832
+ exports2.isDocument = identity2.isDocument;
7833
+ exports2.isMap = identity2.isMap;
7834
+ exports2.isNode = identity2.isNode;
7835
+ exports2.isPair = identity2.isPair;
7836
+ exports2.isScalar = identity2.isScalar;
7837
+ exports2.isSeq = identity2.isSeq;
7818
7838
  exports2.Pair = Pair.Pair;
7819
7839
  exports2.Scalar = Scalar.Scalar;
7820
7840
  exports2.YAMLMap = YAMLMap.YAMLMap;
@@ -7833,6 +7853,48 @@ var require_dist = __commonJS({
7833
7853
  });
7834
7854
 
7835
7855
  // src/git.ts
7856
+ var git_exports = {};
7857
+ __export(git_exports, {
7858
+ branchExists: () => branchExists,
7859
+ checkoutBranch: () => checkoutBranch,
7860
+ createAndCheckoutBranch: () => createAndCheckoutBranch,
7861
+ createBranch: () => createBranch,
7862
+ deleteBranch: () => deleteBranch,
7863
+ getAllChangedFiles: () => getAllChangedFiles,
7864
+ getBranchCommits: () => getBranchCommits,
7865
+ getChangedFilesSince: () => getChangedFilesSince,
7866
+ getCommitHash: () => getCommitHash,
7867
+ getCommitsAheadOfUpstream: () => getCommitsAheadOfUpstream,
7868
+ getCommitsSince: () => getCommitsSince,
7869
+ getCurrentBranch: () => getCurrentBranch,
7870
+ getDefaultBranch: () => getDefaultBranch,
7871
+ getDiffStat: () => getDiffStat,
7872
+ getFullDiff: () => getFullDiff,
7873
+ getGitRoot: () => getGitRoot,
7874
+ getHeadSha: () => getHeadSha,
7875
+ getLatestTag: () => getLatestTag,
7876
+ getOnlineLog: () => getOnlineLog,
7877
+ getPushStats: () => getPushStats,
7878
+ getRecentBranchCommits: () => getRecentBranchCommits,
7879
+ getShortStagedFiles: () => getShortStagedFiles,
7880
+ getStagedDiff: () => getStagedDiff,
7881
+ getStagedDiffShortstat: () => getStagedDiffShortstat,
7882
+ getStagedFileCount: () => getStagedFileCount,
7883
+ getStagedFiles: () => getStagedFiles,
7884
+ getUnstagedFiles: () => getUnstagedFiles,
7885
+ getUpstreamRef: () => getUpstreamRef,
7886
+ getWorkingTreeDiff: () => getWorkingTreeDiff,
7887
+ gitCommit: () => gitCommit,
7888
+ gitPush: () => gitPush,
7889
+ gitPushSetUpstream: () => gitPushSetUpstream,
7890
+ hasStagedChanges: () => hasStagedChanges,
7891
+ isGitRepo: () => isGitRepo,
7892
+ resetHard: () => resetHard,
7893
+ stageAll: () => stageAll,
7894
+ stashPop: () => stashPop,
7895
+ stashPushIfDirty: () => stashPushIfDirty,
7896
+ validateRef: () => validateRef
7897
+ });
7836
7898
  function validateRef(ref, name = "ref") {
7837
7899
  if (ref.startsWith("-")) {
7838
7900
  throw new Error(`Invalid git ref ${name}: starts with hyphen: "${ref}"`);
@@ -7933,8 +7995,18 @@ function gitCommit(message) {
7933
7995
  }
7934
7996
  }
7935
7997
  function gitPush() {
7998
+ const branch = (0, import_child_process2.execFileSync)("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
7999
+ encoding: "utf-8"
8000
+ }).trim();
8001
+ let hasUpstream = false;
8002
+ try {
8003
+ (0, import_child_process2.execFileSync)("git", ["rev-parse", "--abbrev-ref", `${branch}@{upstream}`], { stdio: "pipe" });
8004
+ hasUpstream = true;
8005
+ } catch {
8006
+ }
8007
+ const args = hasUpstream ? ["push"] : ["push", "--set-upstream", "origin", branch];
7936
8008
  try {
7937
- (0, import_child_process2.execFileSync)("git", ["push"], { stdio: "pipe" });
8009
+ (0, import_child_process2.execFileSync)("git", args, { stdio: "pipe" });
7938
8010
  } catch (err) {
7939
8011
  const stderr = err?.stderr?.toString() ?? "";
7940
8012
  if (stderr) process.stderr.write(stderr);
@@ -8032,6 +8104,13 @@ function getStagedDiffShortstat() {
8032
8104
  return { additions: 0, deletions: 0 };
8033
8105
  }
8034
8106
  }
8107
+ function getShortStagedFiles(max = 3) {
8108
+ const output = (0, import_child_process2.execFileSync)("git", ["diff", "--cached", "--name-only"], {
8109
+ encoding: "utf-8"
8110
+ });
8111
+ const all = output.trim().split("\n").filter(Boolean);
8112
+ return { files: all.slice(0, max), total: all.length };
8113
+ }
8035
8114
  function getCommitHash() {
8036
8115
  return (0, import_child_process2.execFileSync)("git", ["rev-parse", "--short", "HEAD"], {
8037
8116
  encoding: "utf-8"
@@ -8042,19 +8121,36 @@ function getPushStats() {
8042
8121
  const branch = (0, import_child_process2.execFileSync)("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
8043
8122
  encoding: "utf-8"
8044
8123
  }).trim();
8045
- const countOutput = (0, import_child_process2.execFileSync)(
8046
- "git",
8047
- ["rev-list", "--count", `origin/${branch}..HEAD`],
8048
- { encoding: "utf-8" }
8049
- ).trim();
8050
- const parsedCount = parseInt(countOutput, 10);
8051
- const commits = Number.isFinite(parsedCount) ? parsedCount : 0;
8124
+ let upstream = null;
8125
+ try {
8126
+ upstream = (0, import_child_process2.execFileSync)(
8127
+ "git",
8128
+ ["rev-parse", "--abbrev-ref", `${branch}@{upstream}`],
8129
+ { encoding: "utf-8", stdio: "pipe" }
8130
+ ).trim();
8131
+ } catch {
8132
+ }
8133
+ if (upstream) {
8134
+ const countOutput = (0, import_child_process2.execFileSync)(
8135
+ "git",
8136
+ ["rev-list", "--count", `${upstream}..HEAD`],
8137
+ { encoding: "utf-8" }
8138
+ ).trim();
8139
+ const parsedCount = parseInt(countOutput, 10);
8140
+ const commits = Number.isFinite(parsedCount) ? parsedCount : 0;
8141
+ const stat2 = (0, import_child_process2.execFileSync)(
8142
+ "git",
8143
+ ["diff", "--shortstat", `${upstream}..HEAD`],
8144
+ { encoding: "utf-8" }
8145
+ ).trim();
8146
+ return { commits, stat: stat2 };
8147
+ }
8052
8148
  const stat = (0, import_child_process2.execFileSync)(
8053
8149
  "git",
8054
- ["diff", "--shortstat", `origin/${branch}..HEAD`],
8150
+ ["diff", "--shortstat", "HEAD~1..HEAD"],
8055
8151
  { encoding: "utf-8" }
8056
8152
  ).trim();
8057
- return { commits, stat };
8153
+ return { commits: 1, stat };
8058
8154
  } catch {
8059
8155
  return null;
8060
8156
  }
@@ -8693,110 +8789,381 @@ var init_monorepo = __esm({
8693
8789
  }
8694
8790
  });
8695
8791
 
8696
- // src/commands/changeset.ts
8697
- var changeset_exports = {};
8698
- __export(changeset_exports, {
8699
- changeset: () => changeset,
8700
- formatChangesetFile: () => formatChangesetFile,
8701
- generateSlug: () => generateSlug,
8702
- mapFilesToPackages: () => mapFilesToPackages
8792
+ // src/smart-diff.ts
8793
+ var smart_diff_exports = {};
8794
+ __export(smart_diff_exports, {
8795
+ classifyFile: () => classifyFile,
8796
+ preprocessDiff: () => preprocessDiff,
8797
+ preprocessDiffWithSizeBudget: () => preprocessDiffWithSizeBudget
8703
8798
  });
8704
- function generateSlug() {
8705
- const pick = (arr) => arr[Math.floor(Math.random() * arr.length)];
8706
- return `${pick(ADJECTIVES)}-${pick(ANIMALS)}-${pick(VERBS)}`;
8799
+ function sanitizeFilepath(path) {
8800
+ return path.replace(/[\x00-\x1F\x7F[\]`]/g, "_").slice(0, 200);
8707
8801
  }
8708
- function mapFilesToPackages(files, workspace) {
8709
- const dirToName = /* @__PURE__ */ new Map();
8802
+ function classifyFile(filepath) {
8803
+ const basename = filepath.split("/").pop() ?? filepath;
8804
+ if (LOCK_FILES.has(basename)) return "lock";
8805
+ if (filepath.endsWith(".map")) return "sourcemap";
8806
+ if (VENDORED_PREFIXES.some((p) => filepath.startsWith(p))) return "vendored";
8807
+ if (GENERATED_PATTERNS.some((p) => p.test(filepath))) return "generated";
8808
+ return "code";
8809
+ }
8810
+ function parseDiffIntoFiles(diff) {
8811
+ const files = [];
8812
+ const parts = diff.split(/^(diff --git .+)$/m);
8813
+ for (let i = 1; i < parts.length; i += 2) {
8814
+ const header = parts[i];
8815
+ const content = parts[i + 1] ?? "";
8816
+ const match = header.match(/diff --git a\/(.+?) b\/(.+)/);
8817
+ const filepath = match?.[2] ?? "unknown";
8818
+ const lines = content.split("\n");
8819
+ let additions = 0;
8820
+ let deletions = 0;
8821
+ for (const line of lines) {
8822
+ if (line.startsWith("+") && !line.startsWith("+++")) additions++;
8823
+ else if (line.startsWith("-") && !line.startsWith("---")) deletions++;
8824
+ }
8825
+ files.push({ filepath, content: header + content, additions, deletions });
8826
+ }
8827
+ return files;
8828
+ }
8829
+ function isMinified(content) {
8830
+ const lines = content.split("\n").filter(
8831
+ (l) => (l.startsWith("+") || l.startsWith("-")) && !l.startsWith("+++") && !l.startsWith("---")
8832
+ );
8833
+ if (lines.length === 0) return false;
8834
+ return lines.some((l) => l.length > 500);
8835
+ }
8836
+ function preprocessDiff(diff) {
8837
+ const files = parseDiffIntoFiles(diff);
8838
+ if (files.length === 0) return { processedDiff: diff, summarized: [], aggressivelySummarized: [], tokensSaved: 0 };
8839
+ const kept = [];
8840
+ const summarized = [];
8841
+ let tokensSaved = 0;
8710
8842
  for (const file of files) {
8711
- const dirName = getPackageForFile(file, workspace);
8712
- if (!dirName || dirToName.has(dirName)) continue;
8713
- for (const pattern of workspace.packages) {
8714
- const hasGlob = /\*/.test(pattern);
8715
- const dir = pattern.replace(/\/?\*\*?$/, "").replace(/\/$/, "");
8716
- const pkgJsonPath = hasGlob ? (0, import_path7.join)(workspace.root, dir, dirName, "package.json") : (0, import_path7.join)(workspace.root, pattern.replace(/\/$/, ""), "package.json");
8717
- try {
8718
- const pkg = JSON.parse((0, import_fs7.readFileSync)(pkgJsonPath, "utf-8"));
8719
- dirToName.set(dirName, pkg.name ?? dirName);
8843
+ const classification = classifyFile(file.filepath);
8844
+ switch (classification) {
8845
+ case "sourcemap":
8846
+ tokensSaved += estimateTokens(file.content);
8847
+ summarized.push(file.filepath);
8848
+ break;
8849
+ case "lock":
8850
+ tokensSaved += estimateTokens(file.content);
8851
+ kept.push(`[lock file updated: ${sanitizeFilepath(file.filepath)} (+${file.additions} \u2212${file.deletions} lines)]
8852
+ `);
8853
+ summarized.push(file.filepath);
8854
+ break;
8855
+ case "generated":
8856
+ tokensSaved += estimateTokens(file.content);
8857
+ kept.push(`[generated: ${sanitizeFilepath(file.filepath)} (+${file.additions} \u2212${file.deletions})]
8858
+ `);
8859
+ summarized.push(file.filepath);
8860
+ break;
8861
+ case "vendored":
8862
+ tokensSaved += estimateTokens(file.content);
8863
+ kept.push(`[vendored: ${sanitizeFilepath(file.filepath)} updated]
8864
+ `);
8865
+ summarized.push(file.filepath);
8866
+ break;
8867
+ case "code":
8868
+ if (isMinified(file.content)) {
8869
+ tokensSaved += estimateTokens(file.content);
8870
+ const sizeKB = Math.round(file.content.length / 1024);
8871
+ kept.push(`[minified asset: ${sanitizeFilepath(file.filepath)} (${sizeKB} KB)]
8872
+ `);
8873
+ summarized.push(file.filepath);
8874
+ } else {
8875
+ kept.push(file.content);
8876
+ }
8720
8877
  break;
8721
- } catch {
8722
- }
8723
- }
8724
- if (!dirToName.has(dirName)) {
8725
- dirToName.set(dirName, dirName);
8726
8878
  }
8727
8879
  }
8728
- return dirToName;
8880
+ return {
8881
+ processedDiff: kept.join(""),
8882
+ summarized,
8883
+ aggressivelySummarized: [],
8884
+ tokensSaved
8885
+ };
8729
8886
  }
8730
- function formatChangesetFile(packages, summary) {
8731
- const frontmatter = packages.map((p) => `"${p.name}": ${p.bump}`).join("\n");
8732
- return `---
8733
- ${frontmatter}
8734
- ---
8735
-
8736
- ${summary}
8887
+ function buildFileSummary(file) {
8888
+ const sizeKB = Math.round(file.content.length / 1024);
8889
+ return `[modified: ${sanitizeFilepath(file.filepath)} \u2014 +${file.additions} \u2212${file.deletions} lines, ~${sizeKB}KB]
8737
8890
  `;
8738
8891
  }
8739
- async function prompt(rl, question) {
8740
- return new Promise((resolve) => rl.question(question, resolve));
8741
- }
8742
- async function changeset(options) {
8743
- const base = options.base ?? "main";
8744
- const apiKey = getApiKey();
8745
- if (!apiKey) {
8746
- console.error("Error: Not authenticated. Run `qc login` first.");
8747
- process.exit(1);
8748
- }
8749
- const { detectWorkspace: detectWorkspace2 } = await Promise.resolve().then(() => (init_monorepo(), monorepo_exports));
8750
- const workspace = detectWorkspace2();
8751
- if (!workspace) {
8752
- console.error(
8753
- "No workspace packages found. Is this a pnpm monorepo?"
8754
- );
8755
- process.exit(1);
8756
- }
8757
- const changedFiles = getChangedFilesSince(base);
8758
- if (changedFiles.length === 0) {
8759
- console.error(`No changes detected vs ${base}.`);
8760
- process.exit(1);
8892
+ function preprocessDiffWithSizeBudget(diff, maxBytes = 5 * 1024 * 1024) {
8893
+ const files = parseDiffIntoFiles(diff);
8894
+ if (files.length === 0) {
8895
+ return { processedDiff: diff, summarized: [], aggressivelySummarized: [], tokensSaved: 0 };
8761
8896
  }
8762
- const packageMap = mapFilesToPackages(changedFiles, workspace);
8763
- const packageNames = Array.from(packageMap.values());
8764
- if (packageNames.length === 0) {
8765
- console.error("No workspace packages detected in changed files.");
8766
- process.exit(1);
8897
+ const entries = [];
8898
+ const summarized = [];
8899
+ let tokensSaved = 0;
8900
+ for (const file of files) {
8901
+ const classification = classifyFile(file.filepath);
8902
+ switch (classification) {
8903
+ case "sourcemap":
8904
+ tokensSaved += estimateTokens(file.content);
8905
+ summarized.push(file.filepath);
8906
+ entries.push({ file, isNoise: true, summaryLine: null });
8907
+ break;
8908
+ case "lock":
8909
+ tokensSaved += estimateTokens(file.content);
8910
+ summarized.push(file.filepath);
8911
+ entries.push({
8912
+ file,
8913
+ isNoise: true,
8914
+ summaryLine: `[lock file updated: ${sanitizeFilepath(file.filepath)} (+${file.additions} \u2212${file.deletions} lines)]
8915
+ `
8916
+ });
8917
+ break;
8918
+ case "generated":
8919
+ tokensSaved += estimateTokens(file.content);
8920
+ summarized.push(file.filepath);
8921
+ entries.push({
8922
+ file,
8923
+ isNoise: true,
8924
+ summaryLine: `[generated: ${sanitizeFilepath(file.filepath)} (+${file.additions} \u2212${file.deletions})]
8925
+ `
8926
+ });
8927
+ break;
8928
+ case "vendored":
8929
+ tokensSaved += estimateTokens(file.content);
8930
+ summarized.push(file.filepath);
8931
+ entries.push({
8932
+ file,
8933
+ isNoise: true,
8934
+ summaryLine: `[vendored: ${sanitizeFilepath(file.filepath)} updated]
8935
+ `
8936
+ });
8937
+ break;
8938
+ case "code":
8939
+ if (isMinified(file.content)) {
8940
+ tokensSaved += estimateTokens(file.content);
8941
+ const sizeKB = Math.round(file.content.length / 1024);
8942
+ summarized.push(file.filepath);
8943
+ entries.push({
8944
+ file,
8945
+ isNoise: true,
8946
+ summaryLine: `[minified asset: ${sanitizeFilepath(file.filepath)} (${sizeKB} KB)]
8947
+ `
8948
+ });
8949
+ } else {
8950
+ entries.push({ file, isNoise: false, summaryLine: null });
8951
+ }
8952
+ break;
8953
+ }
8767
8954
  }
8768
- const commits = getOnlineLog(base);
8769
- const diff = getFullDiff(base);
8770
- const commitCount = commits.split("\n").filter(Boolean).length;
8771
- console.error(
8772
- `Analyzing changes vs ${base}... ${commitCount} commit(s), ${packageNames.length} package(s) changed`
8773
- );
8774
- const client = new ApiClient({ apiKey });
8775
- let result;
8776
- const msg = (e) => e instanceof Error ? e.message : String(e);
8777
- const isTransient = (m) => /invalid json|no changeset|unexpected response|ai worker|timeout|502|503|504/i.test(m);
8778
- let attempts = 0;
8779
- while (true) {
8780
- try {
8781
- result = await client.generateChangeset({
8782
- diff,
8783
- packages: packageNames,
8784
- commits,
8785
- model: options.model
8786
- });
8787
- break;
8788
- } catch (err) {
8789
- const m = msg(err);
8790
- if (!isTransient(m)) {
8791
- console.error(m);
8792
- process.exit(1);
8793
- }
8794
- if (attempts === 0) {
8795
- attempts++;
8796
- continue;
8955
+ const aggressiveMap = /* @__PURE__ */ new Map();
8956
+ function buildOutput() {
8957
+ const parts = [];
8958
+ for (const entry of entries) {
8959
+ if (entry.isNoise) {
8960
+ if (entry.summaryLine !== null) parts.push(entry.summaryLine);
8961
+ } else if (aggressiveMap.has(entry.file.filepath)) {
8962
+ parts.push(aggressiveMap.get(entry.file.filepath));
8963
+ } else {
8964
+ parts.push(entry.file.content);
8797
8965
  }
8798
- console.error(m);
8799
- process.exit(1);
8966
+ }
8967
+ return parts.join("");
8968
+ }
8969
+ const codeEntries = entries.filter((e) => !e.isNoise);
8970
+ let output = buildOutput();
8971
+ if (output.length <= maxBytes) {
8972
+ return {
8973
+ processedDiff: output,
8974
+ summarized,
8975
+ aggressivelySummarized: [],
8976
+ tokensSaved
8977
+ };
8978
+ }
8979
+ const TIER1_THRESHOLD = 5 * 1024;
8980
+ for (const entry of codeEntries) {
8981
+ if (entry.file.content.length > TIER1_THRESHOLD && !aggressiveMap.has(entry.file.filepath)) {
8982
+ tokensSaved += estimateTokens(entry.file.content);
8983
+ aggressiveMap.set(entry.file.filepath, buildFileSummary(entry.file));
8984
+ }
8985
+ }
8986
+ output = buildOutput();
8987
+ if (output.length <= maxBytes) {
8988
+ return {
8989
+ processedDiff: output,
8990
+ summarized,
8991
+ aggressivelySummarized: [...aggressiveMap.keys()],
8992
+ tokensSaved
8993
+ };
8994
+ }
8995
+ const TIER2_THRESHOLD = 2 * 1024;
8996
+ for (const entry of codeEntries) {
8997
+ if (entry.file.content.length > TIER2_THRESHOLD && !aggressiveMap.has(entry.file.filepath)) {
8998
+ tokensSaved += estimateTokens(entry.file.content);
8999
+ aggressiveMap.set(entry.file.filepath, buildFileSummary(entry.file));
9000
+ }
9001
+ }
9002
+ output = buildOutput();
9003
+ if (output.length <= maxBytes) {
9004
+ return {
9005
+ processedDiff: output,
9006
+ summarized,
9007
+ aggressivelySummarized: [...aggressiveMap.keys()],
9008
+ tokensSaved
9009
+ };
9010
+ }
9011
+ for (const entry of codeEntries) {
9012
+ if (!aggressiveMap.has(entry.file.filepath)) {
9013
+ tokensSaved += estimateTokens(entry.file.content);
9014
+ aggressiveMap.set(entry.file.filepath, buildFileSummary(entry.file));
9015
+ }
9016
+ }
9017
+ return {
9018
+ processedDiff: buildOutput(),
9019
+ summarized,
9020
+ aggressivelySummarized: [...aggressiveMap.keys()],
9021
+ tokensSaved
9022
+ };
9023
+ }
9024
+ var LOCK_FILES, GENERATED_PATTERNS, VENDORED_PREFIXES;
9025
+ var init_smart_diff = __esm({
9026
+ "src/smart-diff.ts"() {
9027
+ "use strict";
9028
+ init_dist();
9029
+ LOCK_FILES = /* @__PURE__ */ new Set([
9030
+ "pnpm-lock.yaml",
9031
+ "package-lock.json",
9032
+ "yarn.lock",
9033
+ "Cargo.lock",
9034
+ "Gemfile.lock",
9035
+ "poetry.lock",
9036
+ "composer.lock",
9037
+ "bun.lockb",
9038
+ "shrinkwrap.json"
9039
+ ]);
9040
+ GENERATED_PATTERNS = [
9041
+ /\.generated\.\w+$/,
9042
+ /\.g\.dart$/,
9043
+ /\.pb\.go$/,
9044
+ /\.pb\.ts$/,
9045
+ /(^|\/)\.prisma\/client\//,
9046
+ /\/generated\//
9047
+ ];
9048
+ VENDORED_PREFIXES = ["vendor/", "third_party/", "node_modules/"];
9049
+ }
9050
+ });
9051
+
9052
+ // src/commands/changeset.ts
9053
+ var changeset_exports = {};
9054
+ __export(changeset_exports, {
9055
+ changeset: () => changeset,
9056
+ formatChangesetFile: () => formatChangesetFile,
9057
+ generateSlug: () => generateSlug,
9058
+ mapFilesToPackages: () => mapFilesToPackages
9059
+ });
9060
+ function generateSlug() {
9061
+ const pick = (arr) => arr[Math.floor(Math.random() * arr.length)];
9062
+ return `${pick(ADJECTIVES)}-${pick(ANIMALS)}-${pick(VERBS)}`;
9063
+ }
9064
+ function mapFilesToPackages(files, workspace) {
9065
+ const dirToName = /* @__PURE__ */ new Map();
9066
+ for (const file of files) {
9067
+ const dirName = getPackageForFile(file, workspace);
9068
+ if (!dirName || dirToName.has(dirName)) continue;
9069
+ for (const pattern of workspace.packages) {
9070
+ const hasGlob = /\*/.test(pattern);
9071
+ const dir = pattern.replace(/\/?\*\*?$/, "").replace(/\/$/, "");
9072
+ const pkgJsonPath = hasGlob ? (0, import_path7.join)(workspace.root, dir, dirName, "package.json") : (0, import_path7.join)(workspace.root, pattern.replace(/\/$/, ""), "package.json");
9073
+ try {
9074
+ const pkg = JSON.parse((0, import_fs7.readFileSync)(pkgJsonPath, "utf-8"));
9075
+ dirToName.set(dirName, pkg.name ?? dirName);
9076
+ break;
9077
+ } catch {
9078
+ }
9079
+ }
9080
+ if (!dirToName.has(dirName)) {
9081
+ dirToName.set(dirName, dirName);
9082
+ }
9083
+ }
9084
+ return dirToName;
9085
+ }
9086
+ function formatChangesetFile(packages, summary) {
9087
+ const frontmatter = packages.map((p) => `"${p.name}": ${p.bump}`).join("\n");
9088
+ return `---
9089
+ ${frontmatter}
9090
+ ---
9091
+
9092
+ ${summary}
9093
+ `;
9094
+ }
9095
+ async function prompt(rl, question) {
9096
+ return new Promise((resolve) => rl.question(question, resolve));
9097
+ }
9098
+ async function changeset(options) {
9099
+ const base = options.base ?? "main";
9100
+ const apiKey = getApiKey();
9101
+ if (!apiKey) {
9102
+ console.error("Error: Not authenticated. Run `qc login` first.");
9103
+ process.exit(1);
9104
+ }
9105
+ const { detectWorkspace: detectWorkspace2 } = await Promise.resolve().then(() => (init_monorepo(), monorepo_exports));
9106
+ const workspace = detectWorkspace2();
9107
+ if (!workspace) {
9108
+ console.error(
9109
+ "No workspace packages found. Is this a pnpm monorepo?"
9110
+ );
9111
+ process.exit(1);
9112
+ }
9113
+ const changedFiles = getChangedFilesSince(base);
9114
+ if (changedFiles.length === 0) {
9115
+ console.error(`No commits with file changes detected on this branch vs ${base}.`);
9116
+ console.error(`Tip: \`qc changeset\` requires committed changes (not just staged files).`);
9117
+ console.error(` Commit first with \`qc\`, then run \`qc changeset\`.`);
9118
+ process.exit(1);
9119
+ }
9120
+ const packageMap = mapFilesToPackages(changedFiles, workspace);
9121
+ const packageNames = Array.from(packageMap.values());
9122
+ if (packageNames.length === 0) {
9123
+ console.error("No workspace packages detected in changed files.");
9124
+ process.exit(1);
9125
+ }
9126
+ const commits = getOnlineLog(base);
9127
+ const commitCount = commits.split("\n").filter(Boolean).length;
9128
+ const { preprocessDiffWithSizeBudget: preprocessDiffWithSizeBudget2 } = await Promise.resolve().then(() => (init_smart_diff(), smart_diff_exports));
9129
+ const { getDiffStat: getDiffStat2, getFullDiff: getFullDiff2 } = await Promise.resolve().then(() => (init_git(), git_exports));
9130
+ const diffStat = getDiffStat2(base);
9131
+ const rawDiff = getFullDiff2(base);
9132
+ const { processedDiff } = preprocessDiffWithSizeBudget2(rawDiff, 6e4);
9133
+ const diff = `DIFF STAT:
9134
+ ${diffStat}
9135
+
9136
+ DETAILED DIFF (may be summarized for large changes):
9137
+ ${processedDiff}`;
9138
+ console.error(
9139
+ `Analyzing changes vs ${base}... ${commitCount} commit(s), ${packageNames.length} package(s) changed`
9140
+ );
9141
+ const client = new ApiClient({ apiKey });
9142
+ let result;
9143
+ const msg = (e) => e instanceof Error ? e.message : String(e);
9144
+ const isTransient = (m) => /invalid json|no changeset|unexpected response|ai worker|timeout|502|503|504/i.test(m);
9145
+ let attempts = 0;
9146
+ while (true) {
9147
+ try {
9148
+ result = await client.generateChangeset({
9149
+ diff,
9150
+ packages: packageNames,
9151
+ commits,
9152
+ model: options.model
9153
+ });
9154
+ break;
9155
+ } catch (err) {
9156
+ const m = msg(err);
9157
+ if (!isTransient(m)) {
9158
+ console.error(m);
9159
+ process.exit(1);
9160
+ }
9161
+ if (attempts === 0) {
9162
+ attempts++;
9163
+ continue;
9164
+ }
9165
+ console.error(m);
9166
+ process.exit(1);
8800
9167
  }
8801
9168
  }
8802
9169
  const resultNames = new Set(result.packages.map((p) => p.name));
@@ -9261,6 +9628,193 @@ var require_picocolors = __commonJS({
9261
9628
  }
9262
9629
  });
9263
9630
 
9631
+ // src/ui-theme.ts
9632
+ function overlayTypeColors(base, custom) {
9633
+ if (!custom || Object.keys(custom).length === 0) return { ...base };
9634
+ const next = { ...base };
9635
+ const pmap = import_picocolors.default;
9636
+ for (const [key, raw] of Object.entries(custom)) {
9637
+ const name = typeof raw === "string" ? raw.trim().toLowerCase() : "";
9638
+ if (!name) continue;
9639
+ const fn = pmap[name];
9640
+ if (typeof fn === "function") {
9641
+ next[key] = fn;
9642
+ }
9643
+ }
9644
+ return next;
9645
+ }
9646
+ function buildVibrant() {
9647
+ return {
9648
+ step: import_picocolors.default.dim,
9649
+ success: import_picocolors.default.greenBright,
9650
+ error: import_picocolors.default.redBright,
9651
+ dim: import_picocolors.default.dim,
9652
+ bullet: import_picocolors.default.greenBright,
9653
+ inlineCode: import_picocolors.default.magentaBright,
9654
+ scope: (s) => import_picocolors.default.bold(import_picocolors.default.yellow(s)),
9655
+ strong: import_picocolors.default.bold,
9656
+ additions: import_picocolors.default.greenBright,
9657
+ deletions: import_picocolors.default.redBright,
9658
+ branchName: (s) => import_picocolors.default.bold(import_picocolors.default.magenta(s)),
9659
+ commitHash: import_picocolors.default.dim,
9660
+ boxBorder: import_picocolors.default.dim,
9661
+ boxBorderAccent: import_picocolors.default.cyanBright,
9662
+ spinner: {
9663
+ aiGenerate: import_picocolors.default.cyanBright,
9664
+ branchGen: import_picocolors.default.cyanBright,
9665
+ gitOp: import_picocolors.default.blueBright,
9666
+ localProvider: import_picocolors.default.magentaBright,
9667
+ smartDiff: import_picocolors.default.dim
9668
+ },
9669
+ type: {
9670
+ feat: (s) => import_picocolors.default.bold(import_picocolors.default.cyanBright(s)),
9671
+ fix: (s) => import_picocolors.default.bold(import_picocolors.default.redBright(s)),
9672
+ perf: (s) => import_picocolors.default.bold(import_picocolors.default.magentaBright(s)),
9673
+ refactor: (s) => import_picocolors.default.bold(import_picocolors.default.yellow(s)),
9674
+ docs: (s) => import_picocolors.default.bold(import_picocolors.default.blue(s)),
9675
+ test: (s) => import_picocolors.default.bold(import_picocolors.default.green(s)),
9676
+ chore: (s) => import_picocolors.default.dim(import_picocolors.default.bold(import_picocolors.default.white(s))),
9677
+ ci: (s) => import_picocolors.default.dim(import_picocolors.default.bold(import_picocolors.default.cyan(s))),
9678
+ style: (s) => import_picocolors.default.dim(import_picocolors.default.bold(import_picocolors.default.magenta(s)))
9679
+ }
9680
+ };
9681
+ }
9682
+ function buildMuted() {
9683
+ return {
9684
+ step: import_picocolors.default.dim,
9685
+ success: import_picocolors.default.green,
9686
+ error: import_picocolors.default.red,
9687
+ dim: import_picocolors.default.dim,
9688
+ bullet: import_picocolors.default.green,
9689
+ inlineCode: import_picocolors.default.magenta,
9690
+ scope: (s) => import_picocolors.default.bold(import_picocolors.default.yellow(s)),
9691
+ strong: import_picocolors.default.bold,
9692
+ additions: import_picocolors.default.green,
9693
+ deletions: import_picocolors.default.red,
9694
+ branchName: (s) => import_picocolors.default.bold(import_picocolors.default.magenta(s)),
9695
+ commitHash: import_picocolors.default.dim,
9696
+ boxBorder: import_picocolors.default.dim,
9697
+ boxBorderAccent: import_picocolors.default.cyan,
9698
+ spinner: {
9699
+ aiGenerate: import_picocolors.default.cyan,
9700
+ branchGen: import_picocolors.default.cyan,
9701
+ gitOp: import_picocolors.default.blue,
9702
+ localProvider: import_picocolors.default.magenta,
9703
+ smartDiff: import_picocolors.default.dim
9704
+ },
9705
+ type: {
9706
+ feat: (s) => import_picocolors.default.bold(import_picocolors.default.cyan(s)),
9707
+ fix: (s) => import_picocolors.default.bold(import_picocolors.default.red(s)),
9708
+ perf: (s) => import_picocolors.default.bold(import_picocolors.default.magenta(s)),
9709
+ refactor: (s) => import_picocolors.default.bold(import_picocolors.default.yellow(s)),
9710
+ docs: (s) => import_picocolors.default.bold(import_picocolors.default.blue(s)),
9711
+ test: (s) => import_picocolors.default.bold(import_picocolors.default.green(s)),
9712
+ chore: (s) => import_picocolors.default.dim(import_picocolors.default.bold(import_picocolors.default.white(s))),
9713
+ ci: (s) => import_picocolors.default.dim(import_picocolors.default.bold(import_picocolors.default.cyan(s))),
9714
+ style: (s) => import_picocolors.default.dim(import_picocolors.default.bold(import_picocolors.default.magenta(s)))
9715
+ }
9716
+ };
9717
+ }
9718
+ function buildMono() {
9719
+ const bold = import_picocolors.default.bold;
9720
+ const dim = import_picocolors.default.dim;
9721
+ return {
9722
+ step: dim,
9723
+ success: bold,
9724
+ error: bold,
9725
+ dim,
9726
+ bullet: bold,
9727
+ inlineCode: bold,
9728
+ scope: bold,
9729
+ strong: bold,
9730
+ additions: bold,
9731
+ deletions: bold,
9732
+ branchName: bold,
9733
+ commitHash: dim,
9734
+ boxBorder: dim,
9735
+ boxBorderAccent: bold,
9736
+ spinner: {
9737
+ aiGenerate: identity,
9738
+ branchGen: identity,
9739
+ gitOp: identity,
9740
+ localProvider: identity,
9741
+ smartDiff: dim
9742
+ },
9743
+ type: {
9744
+ feat: bold,
9745
+ fix: bold,
9746
+ perf: bold,
9747
+ refactor: bold,
9748
+ docs: bold,
9749
+ test: bold,
9750
+ chore: dim,
9751
+ ci: dim,
9752
+ style: dim
9753
+ }
9754
+ };
9755
+ }
9756
+ function applyAdaptive(theme, bg) {
9757
+ if (bg !== "light") return theme;
9758
+ return {
9759
+ ...theme,
9760
+ boxBorder: import_picocolors.default.dim,
9761
+ boxBorderAccent: import_picocolors.default.blue,
9762
+ type: {
9763
+ ...theme.type,
9764
+ feat: (s) => theme.strong(import_picocolors.default.cyan(s)),
9765
+ fix: (s) => theme.strong(import_picocolors.default.red(s)),
9766
+ perf: (s) => theme.strong(import_picocolors.default.magenta(s))
9767
+ }
9768
+ };
9769
+ }
9770
+ function getTheme(name, adaptive) {
9771
+ let base;
9772
+ if (name === "muted") base = buildMuted();
9773
+ else if (name === "mono") base = buildMono();
9774
+ else base = buildVibrant();
9775
+ if (!adaptive) return base;
9776
+ return applyAdaptive(base, detectTerminalBackground());
9777
+ }
9778
+ function detectTerminalBackground() {
9779
+ const raw = process.env.COLORFGBG;
9780
+ if (!raw) return "unknown";
9781
+ const parts = raw.split(";").map((p) => p.trim());
9782
+ if (parts.length < 2) return "unknown";
9783
+ const last = parts[parts.length - 1];
9784
+ const n = parseInt(last, 10);
9785
+ if (!Number.isFinite(n)) return "unknown";
9786
+ if (n >= 232 && n <= 255) return n >= 244 ? "light" : "dark";
9787
+ if (n >= 16 && n <= 231) {
9788
+ const i = n - 16;
9789
+ const r = Math.floor(i / 36) / 5;
9790
+ const g = Math.floor(i % 36 / 6) / 5;
9791
+ const b = i % 6 / 5;
9792
+ const luminance = 0.299 * r + 0.587 * g + 0.114 * b;
9793
+ return luminance >= 0.55 ? "light" : "dark";
9794
+ }
9795
+ if (n >= 8 && n <= 15) return "light";
9796
+ if (n >= 0 && n <= 7) return "dark";
9797
+ return "unknown";
9798
+ }
9799
+ function resolveTheme(opts) {
9800
+ if (opts.noColor) return getTheme("mono", false);
9801
+ const baseName = opts.name ?? "vibrant";
9802
+ const adaptive = opts.adaptive ?? true;
9803
+ let theme = getTheme(baseName, adaptive);
9804
+ if (opts.typeColors && Object.keys(opts.typeColors).length > 0) {
9805
+ theme = { ...theme, type: overlayTypeColors(theme.type, opts.typeColors) };
9806
+ }
9807
+ return theme;
9808
+ }
9809
+ var import_picocolors, identity;
9810
+ var init_ui_theme = __esm({
9811
+ "src/ui-theme.ts"() {
9812
+ "use strict";
9813
+ import_picocolors = __toESM(require_picocolors());
9814
+ identity = (s) => s;
9815
+ }
9816
+ });
9817
+
9264
9818
  // src/ui.ts
9265
9819
  function hasCliNoColor() {
9266
9820
  try {
@@ -9274,16 +9828,21 @@ function getTerminalWidth() {
9274
9828
  }
9275
9829
  function createUI(options) {
9276
9830
  const isColor = options.isTTY && !options.noColor;
9277
- const wrap = (fn) => (s) => isColor ? fn(s) : s;
9831
+ const theme = resolveTheme({
9832
+ name: options.themeName,
9833
+ adaptive: options.adaptive,
9834
+ noColor: !isColor,
9835
+ typeColors: options.typeColors
9836
+ });
9278
9837
  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)
9838
+ step: (msg) => isColor ? `${theme.step("\u203A")} ${theme.dim(msg)}` : `\u203A ${msg}`,
9839
+ success: (msg) => isColor ? `${theme.success("\u2713")} ${msg}` : `\u2713 ${msg}`,
9840
+ error: (msg) => isColor ? `${theme.error("\u2717")} ${msg}` : `\u2717 ${msg}`,
9841
+ dim: (msg) => isColor ? theme.dim(msg) : msg,
9842
+ bold: (msg) => isColor ? theme.strong(msg) : msg,
9843
+ commitType: (t) => isColor ? (theme.type[t] ?? theme.type.feat ?? ((s) => s))(t) : t,
9844
+ commitScope: (scope) => isColor ? theme.scope(scope) : scope,
9845
+ accent: (msg) => isColor ? theme.inlineCode(msg) : msg
9287
9846
  };
9288
9847
  function createSpinner(message, write = (s) => process.stderr.write(s)) {
9289
9848
  let frame = 0;
@@ -9294,7 +9853,7 @@ function createUI(options) {
9294
9853
  if (!options.isTTY) return;
9295
9854
  interval = setInterval(() => {
9296
9855
  const f = SPINNER_FRAMES2[frame++ % SPINNER_FRAMES2.length];
9297
- write(`\r${format.step(message)} ${isColor ? import_picocolors.default.cyan(f) : f}`);
9856
+ write(`\r${format.step(message)} ${isColor ? theme.spinner.aiGenerate(f) : f}`);
9298
9857
  }, 80);
9299
9858
  },
9300
9859
  stop(finalMessage) {
@@ -9317,22 +9876,27 @@ function createUI(options) {
9317
9876
  error: (msg) => process.stderr.write(format.error(msg) + "\n"),
9318
9877
  dim: (msg) => process.stderr.write(format.dim(msg) + "\n")
9319
9878
  };
9320
- return { isColor, format, spinner: createSpinner, log };
9879
+ return { isColor, format, spinner: createSpinner, log, theme };
9321
9880
  }
9322
9881
  function getUI() {
9323
9882
  if (!_defaultUI) {
9883
+ const cfg = getConfig();
9324
9884
  _defaultUI = createUI({
9325
9885
  isTTY: !!process.stderr.isTTY,
9326
- noColor: !!process.env.NO_COLOR || hasCliNoColor()
9886
+ noColor: !!process.env.NO_COLOR || hasCliNoColor(),
9887
+ themeName: cfg.ui?.theme,
9888
+ adaptive: cfg.ui?.adaptive !== false,
9889
+ typeColors: cfg.ui?.type_colors
9327
9890
  });
9328
9891
  }
9329
9892
  return _defaultUI;
9330
9893
  }
9331
- var import_picocolors, SPINNER_FRAMES2, _defaultUI, ui;
9894
+ var SPINNER_FRAMES2, _defaultUI, ui;
9332
9895
  var init_ui = __esm({
9333
9896
  "src/ui.ts"() {
9334
9897
  "use strict";
9335
- import_picocolors = __toESM(require_picocolors());
9898
+ init_config();
9899
+ init_ui_theme();
9336
9900
  SPINNER_FRAMES2 = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
9337
9901
  ui = new Proxy({}, {
9338
9902
  get(_target, prop) {
@@ -9342,7 +9906,10 @@ var init_ui = __esm({
9342
9906
  }
9343
9907
  });
9344
9908
 
9345
- // src/ui-rich.ts
9909
+ // src/ui-layout.ts
9910
+ function stripAnsi(s) {
9911
+ return s.replace(/\x1b\[[0-9;]*m/g, "");
9912
+ }
9346
9913
  function splitCommitForBox(message) {
9347
9914
  const firstLine = message.split("\n")[0] ?? "";
9348
9915
  const m = firstLine.match(HEADER_RX);
@@ -9354,91 +9921,174 @@ function splitCommitForBox(message) {
9354
9921
  subject: m[4] ?? ""
9355
9922
  };
9356
9923
  }
9357
- function renderFileTree(files, maxFiles) {
9924
+ function colorizePath(filepath, isColor) {
9925
+ if (!isColor) return filepath;
9926
+ const slashIdx = filepath.lastIndexOf("/");
9927
+ const dir = slashIdx >= 0 ? filepath.slice(0, slashIdx + 1) : "";
9928
+ const name = slashIdx >= 0 ? filepath.slice(slashIdx + 1) : filepath;
9929
+ const dotIdx = name.lastIndexOf(".");
9930
+ const ext = dotIdx > 0 ? name.slice(dotIdx) : "";
9931
+ const colorize = EXTENSION_COLORS[ext];
9932
+ const coloredName = colorize ? colorize(name) : name;
9933
+ return (dir ? import_picocolors2.default.dim(dir) : "") + coloredName;
9934
+ }
9935
+ function renderFileTree(files, maxFiles, opts = {}) {
9358
9936
  if (files.length === 0) return "";
9937
+ const isColor = opts.isColor ?? false;
9359
9938
  const lines = [];
9360
9939
  const display = files.slice(0, maxFiles);
9361
- const overflow = Math.max(0, files.length - maxFiles);
9940
+ const overflow = files.length - maxFiles;
9362
9941
  for (let i = 0; i < display.length; i++) {
9363
- const isLast = i === display.length - 1 && overflow === 0;
9942
+ const isLast = i === display.length - 1 && overflow <= 0;
9364
9943
  const connector = isLast ? "\u2514\u2500" : "\u251C\u2500";
9365
- lines.push(` ${connector} ${display[i]}`);
9944
+ const colored = colorizePath(display[i] ?? "", isColor);
9945
+ const connectorRendered = isColor ? import_picocolors2.default.dim(connector) : connector;
9946
+ lines.push(` ${connectorRendered} ${colored}`);
9366
9947
  }
9367
9948
  if (overflow > 0) {
9368
- lines.push(` \u2514\u2500 +${overflow} more files`);
9949
+ const connector = isColor ? import_picocolors2.default.dim("\u2514\u2500") : "\u2514\u2500";
9950
+ const more = isColor ? import_picocolors2.default.dim(`+${overflow} more files`) : `+${overflow} more files`;
9951
+ lines.push(` ${connector} ${more}`);
9369
9952
  }
9370
9953
  return lines.join("\n");
9371
9954
  }
9955
+ function renderStatsLine(stats, isColor, theme) {
9956
+ if (stats.files === 0 && stats.additions === 0 && stats.deletions === 0) return "";
9957
+ const dim = theme?.dim ?? import_picocolors2.default.dim;
9958
+ const addFn = theme?.additions ?? ((s) => import_picocolors2.default.green(s));
9959
+ const delFn = theme?.deletions ?? ((s) => import_picocolors2.default.red(s));
9960
+ const filesText = isColor ? dim(`${stats.files} files`) : `${stats.files} files`;
9961
+ const additions = isColor ? addFn(`+${stats.additions}`) : `+${stats.additions}`;
9962
+ const deletions = isColor ? delFn(`\u2212${stats.deletions}`) : `\u2212${stats.deletions}`;
9963
+ const sep = isColor ? dim(" \xB7 ") : " \xB7 ";
9964
+ let text = `${filesText}${sep}${additions} ${deletions}`;
9965
+ if (stats.tokens !== void 0) {
9966
+ const tokens = isColor ? dim(`${stats.tokens} tokens`) : `${stats.tokens} tokens`;
9967
+ text += `${sep}${tokens}`;
9968
+ }
9969
+ return ` ${text}`;
9970
+ }
9372
9971
  function wrapLine(text, width) {
9373
- if (text.length <= width) return [text];
9972
+ if (stripAnsi(text).length <= width) return [text];
9374
9973
  const result = [];
9375
9974
  let remaining = text;
9376
- while (remaining.length > width) {
9377
- let breakAt = remaining.lastIndexOf(" ", width);
9378
- if (breakAt < width / 2) breakAt = width;
9975
+ while (stripAnsi(remaining).length > width) {
9976
+ let visibleCount = 0;
9977
+ let rawIdx = 0;
9978
+ let lastSpaceRaw = -1;
9979
+ const len = remaining.length;
9980
+ while (rawIdx < len && visibleCount < width) {
9981
+ if (remaining[rawIdx] === "\x1B") {
9982
+ while (rawIdx < len && remaining[rawIdx] !== "m") rawIdx++;
9983
+ if (rawIdx < len) rawIdx++;
9984
+ continue;
9985
+ }
9986
+ if (remaining[rawIdx] === " ") lastSpaceRaw = rawIdx;
9987
+ visibleCount++;
9988
+ rawIdx++;
9989
+ }
9990
+ const breakAt = lastSpaceRaw > 0 && lastSpaceRaw > width / 2 ? lastSpaceRaw : rawIdx;
9379
9991
  result.push(remaining.slice(0, breakAt));
9380
9992
  remaining = remaining.slice(breakAt).trimStart();
9381
9993
  }
9382
9994
  if (remaining) result.push(remaining);
9383
9995
  return result;
9384
9996
  }
9385
- function stripAnsi(s) {
9386
- return s.replace(/\x1b\[[0-9;]*m/g, "");
9997
+ function isImportantCommit(header, body) {
9998
+ if (/BREAKING CHANGE/i.test(body)) return true;
9999
+ if (/^[a-z]+(\([^)]+\))?!:/i.test(header)) return true;
10000
+ return false;
10001
+ }
10002
+ function styleBoxTopRow(box, horizRepeat, isColor, theme) {
10003
+ if (!isColor) return box.topLeft + box.horizontal.repeat(horizRepeat) + box.topRight;
10004
+ const edge = theme?.boxBorder ?? import_picocolors2.default.dim;
10005
+ const corner = theme?.boxBorderAccent ?? edge;
10006
+ return corner(box.topLeft) + edge(box.horizontal.repeat(horizRepeat)) + corner(box.topRight);
9387
10007
  }
9388
- function boxedLine(content, innerWidth, isColor) {
10008
+ function styleBoxBottomRow(box, horizRepeat, isColor, theme) {
10009
+ if (!isColor) return box.bottomLeft + box.horizontal.repeat(horizRepeat) + box.bottomRight;
10010
+ const edge = theme?.boxBorder ?? import_picocolors2.default.dim;
10011
+ const corner = theme?.boxBorderAccent ?? edge;
10012
+ return corner(box.bottomLeft) + edge(box.horizontal.repeat(horizRepeat)) + corner(box.bottomRight);
10013
+ }
10014
+ function boxedLine(vertical, content, innerWidth, isColor, theme) {
9389
10015
  const visibleLen = stripAnsi(content).length;
9390
10016
  const padding = " ".repeat(Math.max(0, innerWidth - visibleLen));
9391
- const border = isColor ? import_picocolors2.default.dim("\u2502") : "\u2502";
10017
+ const border = isColor ? (theme?.boxBorder ?? import_picocolors2.default.dim)(vertical) : vertical;
9392
10018
  return ` ${border} ${content}${padding} ${border}`;
9393
10019
  }
10020
+ function buildHeaderPrefixAndSubject(parsed, headerFirstLine, isColor, theme) {
10021
+ if (!parsed.type) {
10022
+ return { prefix: "", subjectText: headerFirstLine };
10023
+ }
10024
+ const bangPlain = parsed.breaking ? "!" : "";
10025
+ if (parsed.scope) {
10026
+ const prefixPlain2 = `${parsed.type}(${parsed.scope})${bangPlain}: `;
10027
+ if (!isColor) {
10028
+ return { prefix: prefixPlain2, subjectText: parsed.subject };
10029
+ }
10030
+ const typeCell2 = theme ? theme.type[parsed.type] ?? theme.type.feat ?? ((s) => s) : (s) => import_picocolors2.default.bold(import_picocolors2.default.cyan(s));
10031
+ const scopeCell = theme ? theme.scope : (s) => import_picocolors2.default.bold(import_picocolors2.default.yellow(s));
10032
+ const bangCell2 = theme ? parsed.breaking ? theme.error("!") : "" : parsed.breaking ? import_picocolors2.default.bold(import_picocolors2.default.red("!")) : "";
10033
+ const prefixStyled2 = `${typeCell2(parsed.type)}(${scopeCell(parsed.scope)})${bangCell2}: `;
10034
+ return { prefix: prefixStyled2, subjectText: parsed.subject };
10035
+ }
10036
+ const prefixPlain = `${parsed.type}${bangPlain}: `;
10037
+ if (!isColor) {
10038
+ return { prefix: prefixPlain, subjectText: parsed.subject };
10039
+ }
10040
+ const typeCell = theme ? theme.type[parsed.type] ?? theme.type.feat ?? ((s) => s) : (s) => import_picocolors2.default.bold(import_picocolors2.default.cyan(s));
10041
+ const bangCell = theme ? parsed.breaking ? theme.error("!") : "" : parsed.breaking ? import_picocolors2.default.bold(import_picocolors2.default.red("!")) : "";
10042
+ const prefixStyled = `${typeCell(parsed.type)}${bangCell}: `;
10043
+ return { prefix: prefixStyled, subjectText: parsed.subject };
10044
+ }
9394
10045
  function renderBoxedCommit(header, body, opts) {
9395
- if (opts.width < MIN_BOX_WIDTH) {
10046
+ const requestedStyle = opts.style ?? "gradient";
10047
+ const promoted = opts.autoEmphasis !== false && requestedStyle !== "none" && isImportantCommit(header.split("\n")[0] ?? header, body);
10048
+ const style = promoted ? "double" : requestedStyle;
10049
+ if (style === "none" || opts.width < MIN_BOX_WIDTH) {
9396
10050
  const lines2 = [header.split("\n")[0] ?? header];
9397
10051
  if (body) lines2.push("", body);
9398
10052
  return lines2.join("\n");
9399
10053
  }
10054
+ const chars = BOX_CHARS[style];
9400
10055
  const innerWidth = opts.width - 6;
9401
10056
  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");
10057
+ const firstLineHeader = header.split("\n")[0] ?? header;
9404
10058
  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
- }
10059
+ const { prefix: headerPrefix, subjectText } = buildHeaderPrefixAndSubject(
10060
+ parsed,
10061
+ firstLineHeader,
10062
+ opts.isColor,
10063
+ opts.theme
10064
+ );
10065
+ const prefixLen = stripAnsi(headerPrefix).length;
10066
+ const subjectLines = wrapLine(subjectText, Math.max(1, innerWidth - prefixLen));
10067
+ const styledTop = styleBoxTopRow(chars, horiz, opts.isColor, opts.theme);
10068
+ const styledBottom = styleBoxBottomRow(chars, horiz, opts.isColor, opts.theme);
9415
10069
  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));
10070
+ lines.push(" " + styledTop);
10071
+ lines.push(boxedLine(chars.vertical, headerPrefix + (subjectLines[0] ?? ""), innerWidth, opts.isColor, opts.theme));
10072
+ for (let i = 1; i < subjectLines.length; i++) {
10073
+ lines.push(boxedLine(chars.vertical, " " + (subjectLines[i] ?? ""), innerWidth, opts.isColor, opts.theme));
9420
10074
  }
9421
10075
  if (body) {
9422
- lines.push(boxedLine("", innerWidth, opts.isColor));
10076
+ lines.push(boxedLine(chars.vertical, "", innerWidth, opts.isColor, opts.theme));
9423
10077
  for (const bline of body.split("\n")) {
9424
10078
  const trimmed = bline.trim();
9425
10079
  if (!trimmed) continue;
9426
- const rendered = trimmed.replace(/^[-*]\s+/, opts.isColor ? `${import_picocolors2.default.green("\u2022")} ` : "\u2022 ");
10080
+ const bulletChar = opts.isColor ? (opts.theme?.bullet ?? import_picocolors2.default.green)("\u2022") : "\u2022";
10081
+ const rendered = trimmed.replace(/^[-*]\s+/, `${bulletChar} `);
9427
10082
  const wrapped = wrapLine(rendered, innerWidth);
9428
10083
  for (let i = 0; i < wrapped.length; i++) {
9429
- lines.push(boxedLine((i === 0 ? "" : " ") + (wrapped[i] ?? ""), innerWidth, opts.isColor));
10084
+ lines.push(
10085
+ boxedLine(chars.vertical, (i === 0 ? "" : " ") + (wrapped[i] ?? ""), innerWidth, opts.isColor, opts.theme)
10086
+ );
9430
10087
  }
9431
10088
  }
9432
10089
  }
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}`;
10090
+ lines.push(" " + styledBottom);
10091
+ return lines.join("\n");
9442
10092
  }
9443
10093
  function shouldUseRichOutput(opts) {
9444
10094
  if (!opts.isTTY) return false;
@@ -9447,14 +10097,162 @@ function shouldUseRichOutput(opts) {
9447
10097
  if (opts.width < MIN_BOX_WIDTH) return false;
9448
10098
  return true;
9449
10099
  }
9450
- var import_picocolors2, HEADER_RX, MIN_BOX_WIDTH;
9451
- var init_ui_rich = __esm({
9452
- "src/ui-rich.ts"() {
10100
+ var import_picocolors2, HEADER_RX, EXTENSION_COLORS, MIN_BOX_WIDTH, BOX_CHARS;
10101
+ var init_ui_layout = __esm({
10102
+ "src/ui-layout.ts"() {
9453
10103
  "use strict";
9454
10104
  import_picocolors2 = __toESM(require_picocolors());
9455
- init_ui();
9456
10105
  HEADER_RX = /^([a-z]+)(?:\(([^)]+)\))?(!)?:\s*(.*)$/;
10106
+ EXTENSION_COLORS = {
10107
+ ".ts": import_picocolors2.default.cyan,
10108
+ ".mts": import_picocolors2.default.cyan,
10109
+ ".tsx": import_picocolors2.default.cyanBright,
10110
+ ".js": import_picocolors2.default.yellow,
10111
+ ".mjs": import_picocolors2.default.yellow,
10112
+ ".cjs": import_picocolors2.default.yellow,
10113
+ ".jsx": import_picocolors2.default.yellowBright,
10114
+ ".py": import_picocolors2.default.blue,
10115
+ ".rs": import_picocolors2.default.red,
10116
+ ".go": import_picocolors2.default.cyanBright,
10117
+ ".css": import_picocolors2.default.magenta,
10118
+ ".scss": import_picocolors2.default.magenta,
10119
+ ".sass": import_picocolors2.default.magenta,
10120
+ ".html": import_picocolors2.default.redBright,
10121
+ ".md": import_picocolors2.default.green,
10122
+ ".json": (s) => import_picocolors2.default.dim(import_picocolors2.default.cyan(s)),
10123
+ ".yaml": (s) => import_picocolors2.default.dim(import_picocolors2.default.cyan(s)),
10124
+ ".yml": (s) => import_picocolors2.default.dim(import_picocolors2.default.cyan(s)),
10125
+ ".toml": (s) => import_picocolors2.default.dim(import_picocolors2.default.cyan(s)),
10126
+ ".lock": import_picocolors2.default.dim
10127
+ };
9457
10128
  MIN_BOX_WIDTH = 60;
10129
+ BOX_CHARS = {
10130
+ rounded: {
10131
+ topLeft: "\u256D",
10132
+ topRight: "\u256E",
10133
+ bottomLeft: "\u2570",
10134
+ bottomRight: "\u256F",
10135
+ horizontal: "\u2500",
10136
+ vertical: "\u2502"
10137
+ },
10138
+ gradient: {
10139
+ topLeft: "\u256D",
10140
+ topRight: "\u256E",
10141
+ bottomLeft: "\u2570",
10142
+ bottomRight: "\u256F",
10143
+ horizontal: "\u2500",
10144
+ vertical: "\u2502"
10145
+ },
10146
+ double: {
10147
+ topLeft: "\u2554",
10148
+ topRight: "\u2557",
10149
+ bottomLeft: "\u255A",
10150
+ bottomRight: "\u255D",
10151
+ horizontal: "\u2550",
10152
+ vertical: "\u2551"
10153
+ }
10154
+ };
10155
+ }
10156
+ });
10157
+
10158
+ // src/ui-rich.ts
10159
+ function buildUIContext(ui2, config2, args) {
10160
+ return {
10161
+ theme: ui2.theme,
10162
+ animate: args.noAnimate ? "none" : config2.ui?.animate ?? "tasteful",
10163
+ isTTY: !!process.stderr.isTTY,
10164
+ isColor: ui2.isColor,
10165
+ asciiFallback: !ui2.isColor,
10166
+ uniform: config2.ui?.spinner === "uniform"
10167
+ };
10168
+ }
10169
+ function createStageSpinner(opts) {
10170
+ const origCfg = STAGE_CONFIG[opts.stage];
10171
+ const cfg = opts.uniform ? {
10172
+ frames: STAGE_CONFIG.aiGenerate.frames,
10173
+ intervalMs: STAGE_CONFIG.aiGenerate.intervalMs,
10174
+ themeKey: origCfg.themeKey
10175
+ } : origCfg;
10176
+ const intervalMs = Math.max(16, Math.round(cfg.intervalMs * (opts.animate === "full" ? 0.55 : 1)));
10177
+ const frames = !opts.isColor && opts.asciiFallback ? ASCII_FRAMES : cfg.frames;
10178
+ const colorize = opts.isColor && opts.animate !== "none" ? opts.theme.spinner[cfg.themeKey] : (s) => s;
10179
+ const dim = opts.theme.dim;
10180
+ const write = opts.write ?? ((s) => process.stderr.write(s));
10181
+ let frame = 0;
10182
+ let interval = null;
10183
+ return {
10184
+ start() {
10185
+ if (interval) return;
10186
+ if (!opts.isTTY) return;
10187
+ if (opts.animate === "none") return;
10188
+ interval = setInterval(() => {
10189
+ const f = frames[frame++ % frames.length];
10190
+ write(`\r${dim("\u203A")} ${dim(opts.message)} ${colorize(f)}`);
10191
+ }, intervalMs);
10192
+ },
10193
+ stop(finalMessage) {
10194
+ if (interval) {
10195
+ clearInterval(interval);
10196
+ interval = null;
10197
+ }
10198
+ if (opts.isTTY) {
10199
+ write("\r\x1B[2K");
10200
+ }
10201
+ if (finalMessage) {
10202
+ write(finalMessage + "\n");
10203
+ }
10204
+ }
10205
+ };
10206
+ }
10207
+ async function flashSuccess(opts) {
10208
+ const write = opts.write ?? ((s) => process.stderr.write(s));
10209
+ const animate = opts.animate !== "none" && opts.isTTY;
10210
+ const rawFallback = opts.settledMessage ?? opts.theme.success(opts.message);
10211
+ const fallbackLine = animate ? rawFallback : stripAnsi(rawFallback);
10212
+ if (!animate) {
10213
+ write(fallbackLine + "\n");
10214
+ return;
10215
+ }
10216
+ write(opts.theme.success(opts.message));
10217
+ await new Promise((r) => setTimeout(r, opts.flashMs ?? 200));
10218
+ write("\r\x1B[2K");
10219
+ write((opts.settledMessage ?? opts.message) + "\n");
10220
+ }
10221
+ var STAGE_CONFIG, ASCII_FRAMES;
10222
+ var init_ui_rich = __esm({
10223
+ "src/ui-rich.ts"() {
10224
+ "use strict";
10225
+ init_ui();
10226
+ init_ui_layout();
10227
+ init_ui_layout();
10228
+ STAGE_CONFIG = {
10229
+ aiGenerate: {
10230
+ frames: ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"],
10231
+ intervalMs: 80,
10232
+ themeKey: "aiGenerate"
10233
+ },
10234
+ branchGen: {
10235
+ frames: ["\u25F0", "\u25F3", "\u25F2", "\u25F1"],
10236
+ intervalMs: 85,
10237
+ themeKey: "branchGen"
10238
+ },
10239
+ localProvider: {
10240
+ frames: ["\u25D0", "\u25D3", "\u25D1", "\u25D2"],
10241
+ intervalMs: 100,
10242
+ themeKey: "localProvider"
10243
+ },
10244
+ gitOp: {
10245
+ frames: ["\u2190", "\u2196", "\u2191", "\u2197", "\u2192", "\u2198", "\u2193", "\u2199"],
10246
+ intervalMs: 90,
10247
+ themeKey: "gitOp"
10248
+ },
10249
+ smartDiff: {
10250
+ frames: ["\u258F", "\u258E", "\u258D", "\u258C", "\u258B", "\u258A", "\u2589", "\u258A", "\u258B", "\u258C", "\u258D", "\u258E"],
10251
+ intervalMs: 70,
10252
+ themeKey: "smartDiff"
10253
+ }
10254
+ };
10255
+ ASCII_FRAMES = ["|", "/", "-", "\\"];
9458
10256
  }
9459
10257
  });
9460
10258
 
@@ -9503,324 +10301,126 @@ async function interactiveRefineMessage(initial, opts) {
9503
10301
  if (opts.skip) return { action: "accept", message: initial };
9504
10302
  const rl = import_promises.default.createInterface({ input: process.stdin, output: process.stderr });
9505
10303
  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;
10304
+ process.stderr.write(`
10305
+ ${initial}
10306
+
10307
+ `);
10308
+ const choice = (await rl.question("Keep? [Y/n/e]: ")).trim().toLowerCase();
10309
+ if (choice === "n") {
10310
+ return { action: "abort" };
9728
10311
  }
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);
10312
+ if (choice === "e") {
10313
+ process.stderr.write("Enter new message (end with a line containing only .):\n");
10314
+ const lines = [];
10315
+ while (true) {
10316
+ const line = await rl.question("");
10317
+ if (line === ".") break;
10318
+ lines.push(line);
9740
10319
  }
10320
+ const edited = lines.join("\n").trim();
10321
+ return { action: "edit", message: edited.length > 0 ? edited : initial };
9741
10322
  }
9742
- return parts.join("");
10323
+ return { action: "accept", message: initial };
10324
+ } finally {
10325
+ rl.close();
9743
10326
  }
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
- };
10327
+ }
10328
+ async function promptYesNo(question, defaultYes = true) {
10329
+ const rl = import_promises.default.createInterface({ input: process.stdin, output: process.stderr });
10330
+ const suffix = defaultYes ? "[Y/n]" : "[y/N]";
10331
+ try {
10332
+ const answer = (await rl.question(`${question} ${suffix} `)).trim().toLowerCase();
10333
+ if (answer === "n" || answer === "no") return false;
10334
+ if (answer === "y" || answer === "yes") return true;
10335
+ return defaultYes;
10336
+ } finally {
10337
+ rl.close();
9753
10338
  }
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));
10339
+ }
10340
+ async function confirmCommit(prompt2, opts) {
10341
+ if (opts.skip) return { action: "commit" };
10342
+ const rl = import_promises.default.createInterface({ input: process.stdin, output: process.stderr });
10343
+ try {
10344
+ const ans = (await rl.question(prompt2)).trim().toLowerCase();
10345
+ if (ans !== "y" && ans !== "yes") {
10346
+ return { action: "abort" };
9759
10347
  }
10348
+ return { action: "commit" };
10349
+ } finally {
10350
+ rl.close();
9760
10351
  }
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));
10352
+ }
10353
+ function shouldSkipTTYInteraction(hookMode) {
10354
+ return hookMode === true || process.stdin.isTTY !== true;
10355
+ }
10356
+ function logVerboseDiagnostics(dim, verbose, quiet, diagnostics, roundTripMs) {
10357
+ if (!verbose || quiet) return;
10358
+ process.stderr.write(
10359
+ `
10360
+ ${formatVerboseCommitDiagnostics(diagnostics, roundTripMs)}
10361
+ `
10362
+ );
10363
+ dim("(verbose diagnostics on stderr)");
10364
+ }
10365
+ function isDisplayOpts(opts) {
10366
+ return typeof opts === "object" && opts !== null && "log" in opts;
10367
+ }
10368
+ function createSilentLog() {
10369
+ return {
10370
+ step: () => {
10371
+ },
10372
+ success: () => {
10373
+ },
10374
+ error: (msg) => console.error(msg),
10375
+ dim: () => {
9775
10376
  }
10377
+ };
10378
+ }
10379
+ function displayCommitMessage(message, opts) {
10380
+ const display = isDisplayOpts(opts) ? opts : { log: opts, isTTY: false };
10381
+ const log = display.log;
10382
+ const { subject, body } = splitCommitMessageForDisplay(message);
10383
+ const tw = getTerminalWidth();
10384
+ const useRich = shouldUseRichOutput({
10385
+ isTTY: display.isTTY ?? !!process.stderr.isTTY,
10386
+ noColor: display.isColor === false,
10387
+ width: tw,
10388
+ style: display.style ?? "rich"
10389
+ });
10390
+ if (useRich) {
10391
+ const theme = display.theme ?? getUI().theme;
10392
+ const tree = display.stagedFiles && display.stagedFiles.length > 0 ? renderFileTree(display.stagedFiles, 3, { isColor: !!display.isColor }) : "";
10393
+ if (tree) {
10394
+ process.stderr.write(tree + "\n");
10395
+ }
10396
+ const boxed = renderBoxedCommit(subject, body, {
10397
+ width: display.boxWidth ?? Math.min(getTerminalWidth() - 4, 80),
10398
+ isColor: !!display.isColor,
10399
+ style: display.boxStyle ?? "gradient",
10400
+ autoEmphasis: display.autoEmphasis ?? true,
10401
+ theme
10402
+ });
10403
+ process.stderr.write(boxed + "\n");
10404
+ if (display.stats) {
10405
+ process.stderr.write(renderStatsLine(display.stats, !!display.isColor, theme) + "\n");
10406
+ }
10407
+ return;
9776
10408
  }
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));
10409
+ log.success(subject);
10410
+ if (body) {
10411
+ for (const line of body.split("\n")) {
10412
+ log.dim(` ${line}`);
9790
10413
  }
10414
+ process.stderr.write("\n");
9791
10415
  }
9792
- return {
9793
- processedDiff: buildOutput(),
9794
- summarized,
9795
- aggressivelySummarized: [...aggressiveMap.keys()],
9796
- tokensSaved
9797
- };
9798
10416
  }
9799
- var LOCK_FILES, GENERATED_PATTERNS, VENDORED_PREFIXES;
9800
- var init_smart_diff = __esm({
9801
- "src/smart-diff.ts"() {
10417
+ var import_promises;
10418
+ var init_commit_helpers = __esm({
10419
+ "src/commit-helpers.ts"() {
9802
10420
  "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/"];
10421
+ import_promises = __toESM(require("node:readline/promises"));
10422
+ init_ui();
10423
+ init_ui_rich();
9824
10424
  }
9825
10425
  });
9826
10426
 
@@ -10021,6 +10621,8 @@ async function runLocalCommit(args) {
10021
10621
  }
10022
10622
  const config2 = getConfig();
10023
10623
  const excludes = [...config2.excludes ?? [], ...args.exclude];
10624
+ const uiCtx = buildUIContext(ui2, config2, args);
10625
+ const boxStyle = args.boxStyleOverride ?? config2.ui?.box?.style ?? "gradient";
10024
10626
  let diff = getStagedDiff(excludes);
10025
10627
  const changes = getStagedFiles();
10026
10628
  if (!args.noSmartDiff) {
@@ -10078,7 +10680,11 @@ async function runLocalCommit(args) {
10078
10680
  "Cloudflare provider requires api_url. Run: qc config set api_url https://your-worker.workers.dev"
10079
10681
  );
10080
10682
  }
10081
- const spinner = ui2.spinner(`generating commit (${modelDisplay} via ${local.provider})...`);
10683
+ const spinner = createStageSpinner({
10684
+ stage: "localProvider",
10685
+ message: `generating commit (${modelDisplay} via ${local.provider})...`,
10686
+ ...uiCtx
10687
+ });
10082
10688
  if (!silent) spinner.start();
10083
10689
  const t0 = Date.now();
10084
10690
  let res;
@@ -10129,6 +10735,10 @@ async function runLocalCommit(args) {
10129
10735
  isTTY: !!process.stderr.isTTY,
10130
10736
  style: "rich",
10131
10737
  stagedFiles: stagedPaths,
10738
+ boxStyle,
10739
+ autoEmphasis: config2.ui?.box?.auto_emphasis ?? true,
10740
+ theme: ui2.theme,
10741
+ boxWidth: typeof config2.ui?.box?.width === "number" ? config2.ui.box.width : void 0,
10132
10742
  stats: {
10133
10743
  files: stagedPaths.length,
10134
10744
  additions: short.additions,
@@ -10148,15 +10758,39 @@ async function runLocalCommit(args) {
10148
10758
  }
10149
10759
  gitCommit(message);
10150
10760
  const branch = getCurrentBranch();
10151
- log.step(`[${branch} committed]`);
10761
+ const hash = getCommitHash();
10762
+ if (!silent) {
10763
+ await flashSuccess({
10764
+ message: `\u2713 committed ${branch} \xB7 ${hash}`,
10765
+ settledMessage: `${ui2.theme.success("\u2713 committed")}${ui2.theme.dim(` ${branch} \xB7 ${hash}`)}`,
10766
+ theme: ui2.theme,
10767
+ animate: uiCtx.animate,
10768
+ isTTY: uiCtx.isTTY
10769
+ });
10770
+ }
10152
10771
  if (args.push) {
10153
10772
  const pushStats = getPushStats();
10154
10773
  log.step(`pushing to origin/${branch}...`);
10155
10774
  gitPush();
10156
- if (pushStats) {
10157
- log.success(`pushed ${pushStats.commits} commit(s) \xB7 ${pushStats.stat}`);
10158
- } else {
10159
- log.success("pushed");
10775
+ if (!silent) {
10776
+ if (pushStats) {
10777
+ await flashSuccess({
10778
+ message: `\u2713 pushed ${pushStats.commits} commit(s) \xB7 ${pushStats.stat}`,
10779
+ settledMessage: `${ui2.theme.success("\u2713 pushed")}${ui2.theme.dim(
10780
+ ` ${pushStats.commits} commit(s) \xB7 ${pushStats.stat}`
10781
+ )}`,
10782
+ theme: ui2.theme,
10783
+ animate: uiCtx.animate,
10784
+ isTTY: uiCtx.isTTY
10785
+ });
10786
+ } else {
10787
+ await flashSuccess({
10788
+ message: "\u2713 pushed",
10789
+ theme: ui2.theme,
10790
+ animate: uiCtx.animate,
10791
+ isTTY: uiCtx.isTTY
10792
+ });
10793
+ }
10160
10794
  }
10161
10795
  }
10162
10796
  }
@@ -10272,7 +10906,13 @@ async function runLocalBranch(opts) {
10272
10906
  }
10273
10907
  const ui2 = getUI();
10274
10908
  const log = ui2.log;
10275
- const spinner = ui2.spinner(`generating branch name (${opts.model ?? local.model} via ${local.provider})...`);
10909
+ const config2 = getConfig();
10910
+ const branchUiCtx = buildUIContext(ui2, config2, { noAnimate: opts.noAnimate });
10911
+ const spinner = createStageSpinner({
10912
+ stage: "branchGen",
10913
+ message: `generating branch name (${opts.model ?? local.model} via ${local.provider})...`,
10914
+ ...branchUiCtx
10915
+ });
10276
10916
  if (process.stderr.isTTY) spinner.start();
10277
10917
  let final;
10278
10918
  try {
@@ -10322,6 +10962,7 @@ var init_local = __esm({
10322
10962
  init_ui();
10323
10963
  init_commit_helpers();
10324
10964
  init_branch_name();
10965
+ init_ui_rich();
10325
10966
  CONFIG_PATH2 = (0, import_path8.join)((0, import_os4.homedir)(), CONFIG_DIR);
10326
10967
  PROVIDER_URLS = {
10327
10968
  ollama: "http://localhost:11434",
@@ -10356,12 +10997,14 @@ function finalizeGeneratedBranchName(raw) {
10356
10997
  async function runBranch(opts) {
10357
10998
  const ui2 = getUI();
10358
10999
  const log = ui2.log;
11000
+ const config2 = getConfig();
11001
+ const animate = opts.noAnimate ? "none" : config2.ui?.animate ?? "tasteful";
11002
+ const uniformSpinner = config2.ui?.spinner === "uniform";
10359
11003
  if (!isGitRepo()) {
10360
11004
  log.error("Not a git repository.");
10361
11005
  process.exit(1);
10362
11006
  }
10363
11007
  const baseRef = opts.from ?? "HEAD";
10364
- const config2 = getConfig();
10365
11008
  const model = opts.model ?? config2.model;
10366
11009
  const genRules = branchGenerationRules(config2);
10367
11010
  if (opts.rescue) {
@@ -10390,7 +11033,16 @@ async function runBranch(opts) {
10390
11033
  const recent = getRecentBranchCommits(state.commitsAhead);
10391
11034
  const apiKey2 = opts.apiKey ?? getApiKey();
10392
11035
  if (apiKey2) {
10393
- const spinner2 = ui2.spinner(`generating branch name (${model ?? "default"})...`);
11036
+ const spinner2 = createStageSpinner({
11037
+ stage: "branchGen",
11038
+ message: `generating branch name (${model ?? "default"})...`,
11039
+ theme: ui2.theme,
11040
+ animate,
11041
+ isTTY: !!process.stderr.isTTY,
11042
+ isColor: ui2.isColor,
11043
+ asciiFallback: !ui2.isColor,
11044
+ uniform: uniformSpinner
11045
+ });
10394
11046
  if (process.stderr.isTTY) spinner2.start();
10395
11047
  try {
10396
11048
  const client = new ApiClient({ apiKey: apiKey2 });
@@ -10419,7 +11071,16 @@ async function runBranch(opts) {
10419
11071
  "Not authenticated. Run `qc login` first, or configure a local provider for `--rescue`."
10420
11072
  );
10421
11073
  }
10422
- const spinner2 = ui2.spinner(`generating branch name (${model ?? "default"} via local)...`);
11074
+ const spinner2 = createStageSpinner({
11075
+ stage: "branchGen",
11076
+ message: `generating branch name (${model ?? "default"} via local)...`,
11077
+ theme: ui2.theme,
11078
+ animate,
11079
+ isTTY: !!process.stderr.isTTY,
11080
+ isColor: ui2.isColor,
11081
+ asciiFallback: !ui2.isColor,
11082
+ uniform: uniformSpinner
11083
+ });
10423
11084
  if (process.stderr.isTTY) spinner2.start();
10424
11085
  try {
10425
11086
  try {
@@ -10516,13 +11177,23 @@ async function runBranch(opts) {
10516
11177
  noSwitch: opts.noSwitch,
10517
11178
  push: opts.push,
10518
11179
  baseRef,
10519
- rules: genRules
11180
+ rules: genRules,
11181
+ noAnimate: opts.noAnimate
10520
11182
  });
10521
11183
  return;
10522
11184
  }
10523
11185
  throw new Error("Not authenticated. Run `qc login` first, or provide --message.");
10524
11186
  }
10525
- const spinner = ui2.spinner(`generating branch name (${model ?? "default"})...`);
11187
+ const spinner = createStageSpinner({
11188
+ stage: "branchGen",
11189
+ message: `generating branch name (${model ?? "default"})...`,
11190
+ theme: ui2.theme,
11191
+ animate,
11192
+ isTTY: !!process.stderr.isTTY,
11193
+ isColor: ui2.isColor,
11194
+ asciiFallback: !ui2.isColor,
11195
+ uniform: uniformSpinner
11196
+ });
10526
11197
  if (process.stderr.isTTY) spinner.start();
10527
11198
  let result;
10528
11199
  try {
@@ -10560,6 +11231,7 @@ var init_branch2 = __esm({
10560
11231
  init_branch_name();
10561
11232
  init_commit_helpers();
10562
11233
  init_ui();
11234
+ init_ui_rich();
10563
11235
  }
10564
11236
  });
10565
11237
 
@@ -10965,7 +11637,12 @@ async function runBranchGuard(args, log) {
10965
11637
  }
10966
11638
  generateLocalBranchNameFn = generateLocalBranchName2;
10967
11639
  }
10968
- const spinner = ui2.spinner(`generating branch name...`);
11640
+ const guardUiCtx = buildUIContext(ui2, config2, args);
11641
+ const spinner = createStageSpinner({
11642
+ stage: "branchGen",
11643
+ message: "generating branch name...",
11644
+ ...guardUiCtx
11645
+ });
10969
11646
  if (process.stderr.isTTY) spinner.start();
10970
11647
  let rawName;
10971
11648
  let usedFallback = false;
@@ -11075,6 +11752,7 @@ var init_branch_guard = __esm({
11075
11752
  init_branch_name();
11076
11753
  init_ui();
11077
11754
  init_commit_helpers();
11755
+ init_ui_rich();
11078
11756
  }
11079
11757
  });
11080
11758
 
@@ -11101,7 +11779,8 @@ async function runCommit(args) {
11101
11779
  hookMode: !!args.hookMode,
11102
11780
  apiKey: apiKeyFlag ?? getApiKey() ?? void 0,
11103
11781
  model: args.model,
11104
- excludes
11782
+ excludes,
11783
+ noAnimate: args.noAnimate
11105
11784
  },
11106
11785
  log
11107
11786
  );
@@ -11182,7 +11861,13 @@ async function runCommit(args) {
11182
11861
  const skipInteractive = silent || args.quiet || shouldSkipTTYInteraction(args.hookMode);
11183
11862
  const skipConfirm = args.dryRun || messageOnly || silent || args.quiet || shouldSkipTTYInteraction(args.hookMode);
11184
11863
  const modelDisplay = model ?? "default";
11185
- const spinner = ui2.spinner(`generating commit (${modelDisplay})...`);
11864
+ const uiCtx = buildUIContext(ui2, config2, args);
11865
+ const boxStyle = args.boxStyleOverride ?? config2.ui?.box?.style ?? "gradient";
11866
+ const spinner = createStageSpinner({
11867
+ stage: "aiGenerate",
11868
+ message: `generating commit (${modelDisplay})...`,
11869
+ ...uiCtx
11870
+ });
11186
11871
  if (!silent) spinner.start();
11187
11872
  const t0 = Date.now();
11188
11873
  let generatedMessage;
@@ -11226,6 +11911,10 @@ async function runCommit(args) {
11226
11911
  isTTY: !!process.stderr.isTTY,
11227
11912
  style: "rich",
11228
11913
  stagedFiles: stagedPaths,
11914
+ boxStyle,
11915
+ autoEmphasis: config2.ui?.box?.auto_emphasis ?? true,
11916
+ theme: ui2.theme,
11917
+ boxWidth: typeof config2.ui?.box?.width === "number" ? config2.ui.box.width : void 0,
11229
11918
  stats: {
11230
11919
  files: stagedPaths.length,
11231
11920
  additions: short.additions,
@@ -11245,15 +11934,38 @@ async function runCommit(args) {
11245
11934
  gitCommit(message);
11246
11935
  const hash = getCommitHash();
11247
11936
  const branch = getCurrentBranch();
11248
- log.step(`[${branch} ${hash}] committed`);
11937
+ if (!silent) {
11938
+ await flashSuccess({
11939
+ message: `\u2713 committed ${branch} \xB7 ${hash}`,
11940
+ settledMessage: `${ui2.theme.success("\u2713 committed")}${ui2.theme.dim(` ${branch} \xB7 ${hash}`)}`,
11941
+ theme: ui2.theme,
11942
+ animate: uiCtx.animate,
11943
+ isTTY: !!process.stderr.isTTY
11944
+ });
11945
+ }
11249
11946
  if (push) {
11250
11947
  const pushStats = getPushStats();
11251
11948
  log.step(`pushing to origin/${branch}...`);
11252
11949
  gitPush();
11253
- if (pushStats) {
11254
- log.success(`pushed ${pushStats.commits} commit(s) \xB7 ${pushStats.stat}`);
11255
- } else {
11256
- log.success("pushed");
11950
+ if (!silent) {
11951
+ if (pushStats) {
11952
+ await flashSuccess({
11953
+ message: `\u2713 pushed ${pushStats.commits} commit(s) \xB7 ${pushStats.stat}`,
11954
+ settledMessage: `${ui2.theme.success("\u2713 pushed")}${ui2.theme.dim(
11955
+ ` ${pushStats.commits} commit(s) \xB7 ${pushStats.stat}`
11956
+ )}`,
11957
+ theme: ui2.theme,
11958
+ animate: uiCtx.animate,
11959
+ isTTY: !!process.stderr.isTTY
11960
+ });
11961
+ } else {
11962
+ await flashSuccess({
11963
+ message: "\u2713 pushed",
11964
+ theme: ui2.theme,
11965
+ animate: uiCtx.animate,
11966
+ isTTY: !!process.stderr.isTTY
11967
+ });
11968
+ }
11257
11969
  }
11258
11970
  }
11259
11971
  }
@@ -11269,6 +11981,7 @@ var init_commit = __esm({
11269
11981
  init_smart_diff();
11270
11982
  init_commit_helpers();
11271
11983
  init_branch_guard();
11984
+ init_ui_rich();
11272
11985
  }
11273
11986
  });
11274
11987
 
@@ -11285,8 +11998,8 @@ Usage:
11285
11998
  qc Generate commit message and commit (default)
11286
11999
  qc pr Generate PR description from branch commits
11287
12000
  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)
12001
+ qc changeset Generate changesets from branch commits (pnpm monorepo)
12002
+ qc branch Generate and create a named branch from changes
11290
12003
  qc init Install prepare-commit-msg hook
11291
12004
  qc login Sign in via browser
11292
12005
  qc logout Clear local credentials
@@ -11294,11 +12007,13 @@ Usage:
11294
12007
  qc team Team management (info, rules, invite)
11295
12008
  qc config Show/set config
11296
12009
 
11297
- Flags:
12010
+ Run \`qc <command> -h\` for command-specific help.
12011
+
12012
+ Commit flags:
11298
12013
  -p, --push Commit and push
11299
- -a, --all Stage all tracked changes first
12014
+ -a, --all Stage all files (modified + untracked) first
11300
12015
  -m, --message-only Print message only (stdout, no commit)
11301
- -v, --verbose Show diagnostics (model, token estimates, rules) + API round-trip ms on stderr
12016
+ -v, --verbose Show diagnostics (model, tokens, latency)
11302
12017
  -q, --quiet Minimal output
11303
12018
  -n, --dry-run Show message without committing
11304
12019
  -i, --interactive Interactive refinement mode
@@ -11309,28 +12024,15 @@ Flags:
11309
12024
  -t, --type <type> Force commit type
11310
12025
  -S, --scope <scope> Force scope
11311
12026
  -e, --exclude <pat> Exclude files from diff (repeatable)
11312
-
11313
12027
  --no-context Skip commit history context
11314
12028
  --no-smart-diff Skip smart diff preprocessing
11315
12029
  --no-color Disable colors
12030
+ --no-animate Disable spinner animation and success flash
12031
+ --style <name> Box style: rounded | gradient | double | none
11316
12032
  --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
12033
  --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)
12034
+ --allow-protected Bypass protected-branch guard
12035
+ --auto-branch Auto-create branch (no prompt) when on protected branch
11334
12036
 
11335
12037
  Compose short flags: qc -ap (stage all + push), qc -apv (+ verbose)
11336
12038
 
@@ -11343,6 +12045,81 @@ Examples:
11343
12045
  qc -e "*.lock" # exclude lock files
11344
12046
  qc -t fix -S auth # force type and scope
11345
12047
  `;
12048
+ var HELP_PR = `qc pr \u2014 Generate a PR description from branch commits
12049
+
12050
+ Usage:
12051
+ qc pr Generate PR description and print to stdout
12052
+ qc pr --create Generate and open a PR via \`gh\` CLI
12053
+
12054
+ Flags:
12055
+ --base <branch> Base branch to compare against (default: main)
12056
+ --create Create the PR with \`gh pr create\` (requires gh CLI)
12057
+ --model <id> Use specific model
12058
+
12059
+ Examples:
12060
+ qc pr # print PR description
12061
+ qc pr --create # create the PR directly
12062
+ qc pr --base develop # compare against develop
12063
+ `;
12064
+ var HELP_CHANGELOG = `qc changelog \u2014 Generate a changelog from commits since last tag
12065
+
12066
+ Usage:
12067
+ qc changelog Print changelog entry to stdout
12068
+ qc changelog --write Prepend to CHANGELOG.md
12069
+
12070
+ Flags:
12071
+ --from <ref> Start ref (default: latest tag)
12072
+ --to <ref> End ref (default: HEAD)
12073
+ --write Write/prepend to CHANGELOG.md
12074
+ --version <ver> Version label for header (default: derived from --to)
12075
+ --model <id> Use specific model
12076
+
12077
+ Examples:
12078
+ qc changelog # print changelog since last tag
12079
+ qc changelog --write # prepend to CHANGELOG.md
12080
+ qc changelog --from v1.0.0 # since a specific tag
12081
+ `;
12082
+ var HELP_CHANGESET = `qc changeset \u2014 Generate pnpm changesets from branch commits
12083
+
12084
+ Usage:
12085
+ qc changeset Analyze commits on current branch vs base, generate .changeset/ file
12086
+
12087
+ Requires: commits ahead of base branch (not just staged files).
12088
+ Tip: commit your changes first with \`qc\`, then run \`qc changeset\`.
12089
+
12090
+ Flags:
12091
+ --base <branch> Base branch to compare against (default: main)
12092
+ --model <id> Use specific model
12093
+
12094
+ Examples:
12095
+ qc changeset # changeset from commits vs main
12096
+ qc changeset --base develop # compare against develop
12097
+ `;
12098
+ var HELP_BRANCH = `qc branch \u2014 Generate and create a branch with an AI-generated name
12099
+
12100
+ Usage:
12101
+ qc branch Name from staged/unstaged diff
12102
+ qc branch <name> Use explicit name (skip AI)
12103
+ qc branch --message "..." Name from a description (no diff needed)
12104
+ qc branch --from-commits Name from recent commit history
12105
+ qc branch --rescue Move commits off a protected branch
12106
+
12107
+ Flags:
12108
+ --message <text> Generate name from a description
12109
+ --from-commits Use commit log instead of diff for naming
12110
+ --rescue Move existing commits off protected branch to new branch
12111
+ --no-switch Create branch but don't checkout
12112
+ --from <ref> Base from this ref (default: HEAD)
12113
+ -p, --push Push immediately and set upstream
12114
+ -n, --dry-run Show generated name without creating
12115
+
12116
+ Examples:
12117
+ qc branch # name from current changes
12118
+ qc branch -m "add oauth login" # name from description
12119
+ qc branch feat/my-feature # explicit name
12120
+ qc branch --rescue # move commits off main
12121
+ qc branch -np # dry-run (show name only)
12122
+ `;
11346
12123
  var SHORT_FLAGS = {
11347
12124
  p: "push",
11348
12125
  a: "all",
@@ -11405,6 +12182,7 @@ function parseArgs(args) {
11405
12182
  result[key] = val;
11406
12183
  }
11407
12184
  } else if (ch === "h") {
12185
+ if (result.command !== "commit") result.helpFor = result.command;
11408
12186
  result.command = "help";
11409
12187
  } else {
11410
12188
  throw new Error(`Unknown flag: -${ch}`);
@@ -11433,12 +12211,14 @@ function parseArgs(args) {
11433
12211
  continue;
11434
12212
  }
11435
12213
  if (ch === "h") {
12214
+ if (result.command !== "commit") result.helpFor = result.command;
11436
12215
  result.command = "help";
11437
12216
  continue;
11438
12217
  }
11439
12218
  throw new Error(`Unknown flag: -${ch}`);
11440
12219
  }
11441
12220
  if (arg === "--help") {
12221
+ if (result.command !== "commit") result.helpFor = result.command;
11442
12222
  result.command = "help";
11443
12223
  } else if (arg === "--all") {
11444
12224
  result.all = true;
@@ -11517,6 +12297,16 @@ function parseArgs(args) {
11517
12297
  const ex = args[++i];
11518
12298
  if (ex) result.exclude.push(ex);
11519
12299
  } else if (arg === "--no-color") {
12300
+ } else if (arg === "--no-animate") {
12301
+ result.noAnimate = true;
12302
+ } else if (arg === "--style" && i + 1 < args.length) {
12303
+ const v = args[++i];
12304
+ if (v !== "rounded" && v !== "gradient" && v !== "double" && v !== "none") {
12305
+ throw new Error(
12306
+ `Invalid --style value: ${v}. Must be: rounded | gradient | double | none.`
12307
+ );
12308
+ }
12309
+ result.boxStyleOverride = v;
11520
12310
  } else if (arg === "login") {
11521
12311
  result.command = "login";
11522
12312
  subcommandSeen = true;
@@ -11576,7 +12366,13 @@ async function main() {
11576
12366
  }
11577
12367
  const { command, apiKey } = values;
11578
12368
  if (command === "help") {
11579
- console.log(HELP);
12369
+ const subHelp = {
12370
+ pr: HELP_PR,
12371
+ changelog: HELP_CHANGELOG,
12372
+ changeset: HELP_CHANGESET,
12373
+ branch: HELP_BRANCH
12374
+ };
12375
+ console.log(values.helpFor && subHelp[values.helpFor] ? subHelp[values.helpFor] : HELP);
11580
12376
  return;
11581
12377
  }
11582
12378
  if (values.setProvider) {
@@ -11662,7 +12458,8 @@ async function main() {
11662
12458
  push: values.push,
11663
12459
  from: values.from,
11664
12460
  model: values.model,
11665
- apiKey: values.apiKey
12461
+ apiKey: values.apiKey,
12462
+ noAnimate: values.noAnimate
11666
12463
  });
11667
12464
  return;
11668
12465
  }