@gethmy/mcp 2.1.0 → 2.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -26301,6 +26301,8 @@ class HarmonyApiClient {
26301
26301
  params.set("summary", "true");
26302
26302
  if (options?.includeArchived)
26303
26303
  params.set("include_archived", "true");
26304
+ if (options?.labelName)
26305
+ params.set("label_name", options.labelName);
26304
26306
  const query = params.toString() ? `?${params.toString()}` : "";
26305
26307
  return this.request("GET", `/board/${projectId}${query}`);
26306
26308
  }
@@ -27081,6 +27083,20 @@ async function assembleContext(options) {
27081
27083
  }
27082
27084
  } catch {}
27083
27085
  }
27086
+ if (candidates.length < 20) {
27087
+ try {
27088
+ const wsResult = await client3.listMemoryEntities({
27089
+ workspace_id: workspaceId,
27090
+ scope: "workspace",
27091
+ limit: 20
27092
+ });
27093
+ if (wsResult.entities?.length > 0) {
27094
+ const existingIds = new Set(candidates.map((c) => c.id));
27095
+ const additional = wsResult.entities.map(mapToContextEntity).filter((e) => !existingIds.has(e.id));
27096
+ candidates.push(...additional);
27097
+ }
27098
+ } catch {}
27099
+ }
27084
27100
  if (candidates.length === 0) {
27085
27101
  return {
27086
27102
  context: "",
@@ -30743,1524 +30759,143 @@ class HarmonyMCPServer {
30743
30759
  }
30744
30760
  }
30745
30761
 
30746
- // src/tui/setup.ts
30747
- import {
30748
- existsSync as existsSync6,
30749
- lstatSync,
30750
- mkdirSync as mkdirSync4,
30751
- symlinkSync,
30752
- unlinkSync
30753
- } from "node:fs";
30754
- import { homedir as homedir4 } from "node:os";
30755
- import { dirname as dirname2, join as join5 } from "node:path";
30762
+ // src/skills.ts
30763
+ import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "node:fs";
30764
+ import { dirname } from "node:path";
30765
+ var SKILLS_VERSION = "3";
30766
+ var VERSION_MARKER_PREFIX = "<!-- skills-version:";
30767
+ var HARMONY_WORKFLOW_PROMPT = `# Harmony Card Workflow
30756
30768
 
30757
- // ../../node_modules/@clack/core/dist/index.mjs
30758
- var import_sisteransi = __toESM(require_src(), 1);
30759
- var import_picocolors = __toESM(require_picocolors(), 1);
30760
- import { stdin as j, stdout as M } from "node:process";
30761
- import * as g from "node:readline";
30762
- import O from "node:readline";
30763
- import { Writable as X } from "node:stream";
30764
- function DD({ onlyFirst: e = false } = {}) {
30765
- const t = ["[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?(?:\\u0007|\\u001B\\u005C|\\u009C))", "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))"].join("|");
30766
- return new RegExp(t, e ? undefined : "g");
30767
- }
30768
- var uD = DD();
30769
- function P(e) {
30770
- if (typeof e != "string")
30771
- throw new TypeError(`Expected a \`string\`, got \`${typeof e}\``);
30772
- return e.replace(uD, "");
30773
- }
30774
- function L(e) {
30775
- return e && e.__esModule && Object.prototype.hasOwnProperty.call(e, "default") ? e.default : e;
30776
- }
30777
- var W = { exports: {} };
30778
- (function(e) {
30779
- var u = {};
30780
- e.exports = u, u.eastAsianWidth = function(F) {
30781
- var s = F.charCodeAt(0), i = F.length == 2 ? F.charCodeAt(1) : 0, D = s;
30782
- return 55296 <= s && s <= 56319 && 56320 <= i && i <= 57343 && (s &= 1023, i &= 1023, D = s << 10 | i, D += 65536), D == 12288 || 65281 <= D && D <= 65376 || 65504 <= D && D <= 65510 ? "F" : D == 8361 || 65377 <= D && D <= 65470 || 65474 <= D && D <= 65479 || 65482 <= D && D <= 65487 || 65490 <= D && D <= 65495 || 65498 <= D && D <= 65500 || 65512 <= D && D <= 65518 ? "H" : 4352 <= D && D <= 4447 || 4515 <= D && D <= 4519 || 4602 <= D && D <= 4607 || 9001 <= D && D <= 9002 || 11904 <= D && D <= 11929 || 11931 <= D && D <= 12019 || 12032 <= D && D <= 12245 || 12272 <= D && D <= 12283 || 12289 <= D && D <= 12350 || 12353 <= D && D <= 12438 || 12441 <= D && D <= 12543 || 12549 <= D && D <= 12589 || 12593 <= D && D <= 12686 || 12688 <= D && D <= 12730 || 12736 <= D && D <= 12771 || 12784 <= D && D <= 12830 || 12832 <= D && D <= 12871 || 12880 <= D && D <= 13054 || 13056 <= D && D <= 19903 || 19968 <= D && D <= 42124 || 42128 <= D && D <= 42182 || 43360 <= D && D <= 43388 || 44032 <= D && D <= 55203 || 55216 <= D && D <= 55238 || 55243 <= D && D <= 55291 || 63744 <= D && D <= 64255 || 65040 <= D && D <= 65049 || 65072 <= D && D <= 65106 || 65108 <= D && D <= 65126 || 65128 <= D && D <= 65131 || 110592 <= D && D <= 110593 || 127488 <= D && D <= 127490 || 127504 <= D && D <= 127546 || 127552 <= D && D <= 127560 || 127568 <= D && D <= 127569 || 131072 <= D && D <= 194367 || 177984 <= D && D <= 196605 || 196608 <= D && D <= 262141 ? "W" : 32 <= D && D <= 126 || 162 <= D && D <= 163 || 165 <= D && D <= 166 || D == 172 || D == 175 || 10214 <= D && D <= 10221 || 10629 <= D && D <= 10630 ? "Na" : D == 161 || D == 164 || 167 <= D && D <= 168 || D == 170 || 173 <= D && D <= 174 || 176 <= D && D <= 180 || 182 <= D && D <= 186 || 188 <= D && D <= 191 || D == 198 || D == 208 || 215 <= D && D <= 216 || 222 <= D && D <= 225 || D == 230 || 232 <= D && D <= 234 || 236 <= D && D <= 237 || D == 240 || 242 <= D && D <= 243 || 247 <= D && D <= 250 || D == 252 || D == 254 || D == 257 || D == 273 || D == 275 || D == 283 || 294 <= D && D <= 295 || D == 299 || 305 <= D && D <= 307 || D == 312 || 319 <= D && D <= 322 || D == 324 || 328 <= D && D <= 331 || D == 333 || 338 <= D && D <= 339 || 358 <= D && D <= 359 || D == 363 || D == 462 || D == 464 || D == 466 || D == 468 || D == 470 || D == 472 || D == 474 || D == 476 || D == 593 || D == 609 || D == 708 || D == 711 || 713 <= D && D <= 715 || D == 717 || D == 720 || 728 <= D && D <= 731 || D == 733 || D == 735 || 768 <= D && D <= 879 || 913 <= D && D <= 929 || 931 <= D && D <= 937 || 945 <= D && D <= 961 || 963 <= D && D <= 969 || D == 1025 || 1040 <= D && D <= 1103 || D == 1105 || D == 8208 || 8211 <= D && D <= 8214 || 8216 <= D && D <= 8217 || 8220 <= D && D <= 8221 || 8224 <= D && D <= 8226 || 8228 <= D && D <= 8231 || D == 8240 || 8242 <= D && D <= 8243 || D == 8245 || D == 8251 || D == 8254 || D == 8308 || D == 8319 || 8321 <= D && D <= 8324 || D == 8364 || D == 8451 || D == 8453 || D == 8457 || D == 8467 || D == 8470 || 8481 <= D && D <= 8482 || D == 8486 || D == 8491 || 8531 <= D && D <= 8532 || 8539 <= D && D <= 8542 || 8544 <= D && D <= 8555 || 8560 <= D && D <= 8569 || D == 8585 || 8592 <= D && D <= 8601 || 8632 <= D && D <= 8633 || D == 8658 || D == 8660 || D == 8679 || D == 8704 || 8706 <= D && D <= 8707 || 8711 <= D && D <= 8712 || D == 8715 || D == 8719 || D == 8721 || D == 8725 || D == 8730 || 8733 <= D && D <= 8736 || D == 8739 || D == 8741 || 8743 <= D && D <= 8748 || D == 8750 || 8756 <= D && D <= 8759 || 8764 <= D && D <= 8765 || D == 8776 || D == 8780 || D == 8786 || 8800 <= D && D <= 8801 || 8804 <= D && D <= 8807 || 8810 <= D && D <= 8811 || 8814 <= D && D <= 8815 || 8834 <= D && D <= 8835 || 8838 <= D && D <= 8839 || D == 8853 || D == 8857 || D == 8869 || D == 8895 || D == 8978 || 9312 <= D && D <= 9449 || 9451 <= D && D <= 9547 || 9552 <= D && D <= 9587 || 9600 <= D && D <= 9615 || 9618 <= D && D <= 9621 || 9632 <= D && D <= 9633 || 9635 <= D && D <= 9641 || 9650 <= D && D <= 9651 || 9654 <= D && D <= 9655 || 9660 <= D && D <= 9661 || 9664 <= D && D <= 9665 || 9670 <= D && D <= 9672 || D == 9675 || 9678 <= D && D <= 9681 || 9698 <= D && D <= 9701 || D == 9711 || 9733 <= D && D <= 9734 || D == 9737 || 9742 <= D && D <= 9743 || 9748 <= D && D <= 9749 || D == 9756 || D == 9758 || D == 9792 || D == 9794 || 9824 <= D && D <= 9825 || 9827 <= D && D <= 9829 || 9831 <= D && D <= 9834 || 9836 <= D && D <= 9837 || D == 9839 || 9886 <= D && D <= 9887 || 9918 <= D && D <= 9919 || 9924 <= D && D <= 9933 || 9935 <= D && D <= 9953 || D == 9955 || 9960 <= D && D <= 9983 || D == 10045 || D == 10071 || 10102 <= D && D <= 10111 || 11093 <= D && D <= 11097 || 12872 <= D && D <= 12879 || 57344 <= D && D <= 63743 || 65024 <= D && D <= 65039 || D == 65533 || 127232 <= D && D <= 127242 || 127248 <= D && D <= 127277 || 127280 <= D && D <= 127337 || 127344 <= D && D <= 127386 || 917760 <= D && D <= 917999 || 983040 <= D && D <= 1048573 || 1048576 <= D && D <= 1114109 ? "A" : "N";
30783
- }, u.characterLength = function(F) {
30784
- var s = this.eastAsianWidth(F);
30785
- return s == "F" || s == "W" || s == "A" ? 2 : 1;
30786
- };
30787
- function t(F) {
30788
- return F.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[^\uD800-\uDFFF]/g) || [];
30789
- }
30790
- u.length = function(F) {
30791
- for (var s = t(F), i = 0, D = 0;D < s.length; D++)
30792
- i = i + this.characterLength(s[D]);
30793
- return i;
30794
- }, u.slice = function(F, s, i) {
30795
- textLen = u.length(F), s = s || 0, i = i || 1, s < 0 && (s = textLen + s), i < 0 && (i = textLen + i);
30796
- for (var D = "", C = 0, n = t(F), E = 0;E < n.length; E++) {
30797
- var a = n[E], o = u.length(a);
30798
- if (C >= s - (o == 2 ? 1 : 0))
30799
- if (C + o <= i)
30800
- D += a;
30801
- else
30802
- break;
30803
- C += o;
30804
- }
30805
- return D;
30806
- };
30807
- })(W);
30808
- var tD = W.exports;
30809
- var eD = L(tD);
30810
- var FD = function() {
30811
- return /\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62(?:\uDB40\uDC77\uDB40\uDC6C\uDB40\uDC73|\uDB40\uDC73\uDB40\uDC63\uDB40\uDC74|\uDB40\uDC65\uDB40\uDC6E\uDB40\uDC67)\uDB40\uDC7F|(?:\uD83E\uDDD1\uD83C\uDFFF\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB-\uDFFE])|(?:\uD83E\uDDD1\uD83C\uDFFE\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFD\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFC\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFB\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFB\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFC-\uDFFF])|\uD83D\uDC68(?:\uD83C\uDFFB(?:\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF]))|\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFC-\uDFFF])|[\u2695\u2696\u2708]\uFE0F|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))?|(?:\uD83C[\uDFFC-\uDFFF])\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF]))|\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83D\uDC68|(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFE])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])\uFE0F|\u200D(?:(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D[\uDC66\uDC67])|\uD83D[\uDC66\uDC67])|\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC)?|(?:\uD83D\uDC69(?:\uD83C\uDFFB\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|(?:\uD83C[\uDFFC-\uDFFF])\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69]))|\uD83E\uDDD1(?:\uD83C[\uDFFB-\uDFFF])\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1)(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC69(?:\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83E\uDDD1(?:\u200D(?:\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83D\uDC69\u200D\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D[\uDC66\uDC67])|\uD83D\uDC69\u200D\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|(?:\uD83D\uDC41\uFE0F\u200D\uD83D\uDDE8|\uD83E\uDDD1(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|\uD83D\uDC69(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|\uD83D\uDE36\u200D\uD83C\uDF2B|\uD83C\uDFF3\uFE0F\u200D\u26A7|\uD83D\uDC3B\u200D\u2744|(?:(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC6F|\uD83E[\uDD3C\uDDDE\uDDDF])\u200D[\u2640\u2642]|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])\u200D[\u2640\u2642]|\uD83C\uDFF4\u200D\u2620|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])\u200D[\u2640\u2642]|[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u2328\u23CF\u23ED-\u23EF\u23F1\u23F2\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB\u25FC\u2600-\u2604\u260E\u2611\u2618\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u2692\u2694-\u2697\u2699\u269B\u269C\u26A0\u26A7\u26B0\u26B1\u26C8\u26CF\u26D1\u26D3\u26E9\u26F0\u26F1\u26F4\u26F7\u26F8\u2702\u2708\u2709\u270F\u2712\u2714\u2716\u271D\u2721\u2733\u2734\u2744\u2747\u2763\u27A1\u2934\u2935\u2B05-\u2B07\u3030\u303D\u3297\u3299]|\uD83C[\uDD70\uDD71\uDD7E\uDD7F\uDE02\uDE37\uDF21\uDF24-\uDF2C\uDF36\uDF7D\uDF96\uDF97\uDF99-\uDF9B\uDF9E\uDF9F\uDFCD\uDFCE\uDFD4-\uDFDF\uDFF5\uDFF7]|\uD83D[\uDC3F\uDCFD\uDD49\uDD4A\uDD6F\uDD70\uDD73\uDD76-\uDD79\uDD87\uDD8A-\uDD8D\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA\uDECB\uDECD-\uDECF\uDEE0-\uDEE5\uDEE9\uDEF0\uDEF3])\uFE0F|\uD83C\uDFF3\uFE0F\u200D\uD83C\uDF08|\uD83D\uDC69\u200D\uD83D\uDC67|\uD83D\uDC69\u200D\uD83D\uDC66|\uD83D\uDE35\u200D\uD83D\uDCAB|\uD83D\uDE2E\u200D\uD83D\uDCA8|\uD83D\uDC15\u200D\uD83E\uDDBA|\uD83E\uDDD1(?:\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC|\uD83C\uDFFB)?|\uD83D\uDC69(?:\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC|\uD83C\uDFFB)?|\uD83C\uDDFD\uD83C\uDDF0|\uD83C\uDDF6\uD83C\uDDE6|\uD83C\uDDF4\uD83C\uDDF2|\uD83D\uDC08\u200D\u2B1B|\u2764\uFE0F\u200D(?:\uD83D\uDD25|\uD83E\uDE79)|\uD83D\uDC41\uFE0F|\uD83C\uDFF3\uFE0F|\uD83C\uDDFF(?:\uD83C[\uDDE6\uDDF2\uDDFC])|\uD83C\uDDFE(?:\uD83C[\uDDEA\uDDF9])|\uD83C\uDDFC(?:\uD83C[\uDDEB\uDDF8])|\uD83C\uDDFB(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA])|\uD83C\uDDFA(?:\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF])|\uD83C\uDDF9(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF])|\uD83C\uDDF8(?:\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF])|\uD83C\uDDF7(?:\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC])|\uD83C\uDDF5(?:\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE])|\uD83C\uDDF3(?:\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF])|\uD83C\uDDF2(?:\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF])|\uD83C\uDDF1(?:\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE])|\uD83C\uDDF0(?:\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF])|\uD83C\uDDEF(?:\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5])|\uD83C\uDDEE(?:\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9])|\uD83C\uDDED(?:\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA])|\uD83C\uDDEC(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE])|\uD83C\uDDEB(?:\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7])|\uD83C\uDDEA(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA])|\uD83C\uDDE9(?:\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF])|\uD83C\uDDE8(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF])|\uD83C\uDDE7(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF])|\uD83C\uDDE6(?:\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF])|[#\*0-9]\uFE0F\u20E3|\u2764\uFE0F|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])|\uD83C\uDFF4|(?:[\u270A\u270B]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5])(?:\uD83C[\uDFFB-\uDFFF])|(?:[\u261D\u270C\u270D]|\uD83D[\uDD74\uDD90])(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])|[\u270A\u270B]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC08\uDC15\uDC3B\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE2E\uDE35\uDE36\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5]|\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD]|\uD83D\uDC6F|\uD83E[\uDD3C\uDDDE\uDDDF]|[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF84\uDF86-\uDF93\uDFA0-\uDFC1\uDFC5\uDFC6\uDFC8\uDFC9\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC07\uDC09-\uDC14\uDC16-\uDC3A\uDC3C-\uDC3E\uDC40\uDC44\uDC45\uDC51-\uDC65\uDC6A\uDC79-\uDC7B\uDC7D-\uDC80\uDC84\uDC88-\uDC8E\uDC90\uDC92-\uDCA9\uDCAB-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDDA4\uDDFB-\uDE2D\uDE2F-\uDE34\uDE37-\uDE44\uDE48-\uDE4A\uDE80-\uDEA2\uDEA4-\uDEB3\uDEB7-\uDEBF\uDEC1-\uDEC5\uDED0-\uDED2\uDED5-\uDED7\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0D\uDD0E\uDD10-\uDD17\uDD1D\uDD20-\uDD25\uDD27-\uDD2F\uDD3A\uDD3F-\uDD45\uDD47-\uDD76\uDD78\uDD7A-\uDDB4\uDDB7\uDDBA\uDDBC-\uDDCB\uDDD0\uDDE0-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6]|(?:[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u270A\u270B\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF93\uDFA0-\uDFCA\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF4\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC3E\uDC40\uDC42-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDD7A\uDD95\uDD96\uDDA4\uDDFB-\uDE4F\uDE80-\uDEC5\uDECC\uDED0-\uDED2\uDED5-\uDED7\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0C-\uDD3A\uDD3C-\uDD45\uDD47-\uDD78\uDD7A-\uDDCB\uDDCD-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6])|(?:[#\*0-9\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692-\u2697\u2699\u269B\u269C\u26A0\u26A1\u26A7\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD7A\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA4\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED2\uDED5-\uDED7\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0C-\uDD3A\uDD3C-\uDD45\uDD47-\uDD78\uDD7A-\uDDCB\uDDCD-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6])\uFE0F|(?:[\u261D\u26F9\u270A-\u270D]|\uD83C[\uDF85\uDFC2-\uDFC4\uDFC7\uDFCA-\uDFCC]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66-\uDC78\uDC7C\uDC81-\uDC83\uDC85-\uDC87\uDC8F\uDC91\uDCAA\uDD74\uDD75\uDD7A\uDD90\uDD95\uDD96\uDE45-\uDE47\uDE4B-\uDE4F\uDEA3\uDEB4-\uDEB6\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1F\uDD26\uDD30-\uDD39\uDD3C-\uDD3E\uDD77\uDDB5\uDDB6\uDDB8\uDDB9\uDDBB\uDDCD-\uDDCF\uDDD1-\uDDDD])/g;
30812
- };
30813
- var sD = L(FD);
30814
- function p(e, u = {}) {
30815
- if (typeof e != "string" || e.length === 0 || (u = { ambiguousIsNarrow: true, ...u }, e = P(e), e.length === 0))
30816
- return 0;
30817
- e = e.replace(sD(), " ");
30818
- const t = u.ambiguousIsNarrow ? 1 : 2;
30819
- let F = 0;
30820
- for (const s of e) {
30821
- const i = s.codePointAt(0);
30822
- if (i <= 31 || i >= 127 && i <= 159 || i >= 768 && i <= 879)
30823
- continue;
30824
- switch (eD.eastAsianWidth(s)) {
30825
- case "F":
30826
- case "W":
30827
- F += 2;
30828
- break;
30829
- case "A":
30830
- F += t;
30831
- break;
30832
- default:
30833
- F += 1;
30834
- }
30835
- }
30836
- return F;
30837
- }
30838
- var w = 10;
30839
- var N = (e = 0) => (u) => `\x1B[${u + e}m`;
30840
- var I = (e = 0) => (u) => `\x1B[${38 + e};5;${u}m`;
30841
- var R = (e = 0) => (u, t, F) => `\x1B[${38 + e};2;${u};${t};${F}m`;
30842
- var r = { modifier: { reset: [0, 0], bold: [1, 22], dim: [2, 22], italic: [3, 23], underline: [4, 24], overline: [53, 55], inverse: [7, 27], hidden: [8, 28], strikethrough: [9, 29] }, color: { black: [30, 39], red: [31, 39], green: [32, 39], yellow: [33, 39], blue: [34, 39], magenta: [35, 39], cyan: [36, 39], white: [37, 39], blackBright: [90, 39], gray: [90, 39], grey: [90, 39], redBright: [91, 39], greenBright: [92, 39], yellowBright: [93, 39], blueBright: [94, 39], magentaBright: [95, 39], cyanBright: [96, 39], whiteBright: [97, 39] }, bgColor: { bgBlack: [40, 49], bgRed: [41, 49], bgGreen: [42, 49], bgYellow: [43, 49], bgBlue: [44, 49], bgMagenta: [45, 49], bgCyan: [46, 49], bgWhite: [47, 49], bgBlackBright: [100, 49], bgGray: [100, 49], bgGrey: [100, 49], bgRedBright: [101, 49], bgGreenBright: [102, 49], bgYellowBright: [103, 49], bgBlueBright: [104, 49], bgMagentaBright: [105, 49], bgCyanBright: [106, 49], bgWhiteBright: [107, 49] } };
30843
- Object.keys(r.modifier);
30844
- var iD = Object.keys(r.color);
30845
- var CD = Object.keys(r.bgColor);
30846
- [...iD, ...CD];
30847
- function rD() {
30848
- const e = new Map;
30849
- for (const [u, t] of Object.entries(r)) {
30850
- for (const [F, s] of Object.entries(t))
30851
- r[F] = { open: `\x1B[${s[0]}m`, close: `\x1B[${s[1]}m` }, t[F] = r[F], e.set(s[0], s[1]);
30852
- Object.defineProperty(r, u, { value: t, enumerable: false });
30853
- }
30854
- return Object.defineProperty(r, "codes", { value: e, enumerable: false }), r.color.close = "\x1B[39m", r.bgColor.close = "\x1B[49m", r.color.ansi = N(), r.color.ansi256 = I(), r.color.ansi16m = R(), r.bgColor.ansi = N(w), r.bgColor.ansi256 = I(w), r.bgColor.ansi16m = R(w), Object.defineProperties(r, { rgbToAnsi256: { value: (u, t, F) => u === t && t === F ? u < 8 ? 16 : u > 248 ? 231 : Math.round((u - 8) / 247 * 24) + 232 : 16 + 36 * Math.round(u / 255 * 5) + 6 * Math.round(t / 255 * 5) + Math.round(F / 255 * 5), enumerable: false }, hexToRgb: { value: (u) => {
30855
- const t = /[a-f\d]{6}|[a-f\d]{3}/i.exec(u.toString(16));
30856
- if (!t)
30857
- return [0, 0, 0];
30858
- let [F] = t;
30859
- F.length === 3 && (F = [...F].map((i) => i + i).join(""));
30860
- const s = Number.parseInt(F, 16);
30861
- return [s >> 16 & 255, s >> 8 & 255, s & 255];
30862
- }, enumerable: false }, hexToAnsi256: { value: (u) => r.rgbToAnsi256(...r.hexToRgb(u)), enumerable: false }, ansi256ToAnsi: { value: (u) => {
30863
- if (u < 8)
30864
- return 30 + u;
30865
- if (u < 16)
30866
- return 90 + (u - 8);
30867
- let t, F, s;
30868
- if (u >= 232)
30869
- t = ((u - 232) * 10 + 8) / 255, F = t, s = t;
30870
- else {
30871
- u -= 16;
30872
- const C = u % 36;
30873
- t = Math.floor(u / 36) / 5, F = Math.floor(C / 6) / 5, s = C % 6 / 5;
30874
- }
30875
- const i = Math.max(t, F, s) * 2;
30876
- if (i === 0)
30877
- return 30;
30878
- let D = 30 + (Math.round(s) << 2 | Math.round(F) << 1 | Math.round(t));
30879
- return i === 2 && (D += 60), D;
30880
- }, enumerable: false }, rgbToAnsi: { value: (u, t, F) => r.ansi256ToAnsi(r.rgbToAnsi256(u, t, F)), enumerable: false }, hexToAnsi: { value: (u) => r.ansi256ToAnsi(r.hexToAnsi256(u)), enumerable: false } }), r;
30881
- }
30882
- var ED = rD();
30883
- var d = new Set(["\x1B", "›"]);
30884
- var oD = 39;
30885
- var y = "\x07";
30886
- var V = "[";
30887
- var nD = "]";
30888
- var G = "m";
30889
- var _ = `${nD}8;;`;
30890
- var z2 = (e) => `${d.values().next().value}${V}${e}${G}`;
30891
- var K = (e) => `${d.values().next().value}${_}${e}${y}`;
30892
- var aD = (e) => e.split(" ").map((u) => p(u));
30893
- var k = (e, u, t) => {
30894
- const F = [...u];
30895
- let s = false, i = false, D = p(P(e[e.length - 1]));
30896
- for (const [C, n] of F.entries()) {
30897
- const E = p(n);
30898
- if (D + E <= t ? e[e.length - 1] += n : (e.push(n), D = 0), d.has(n) && (s = true, i = F.slice(C + 1).join("").startsWith(_)), s) {
30899
- i ? n === y && (s = false, i = false) : n === G && (s = false);
30900
- continue;
30901
- }
30902
- D += E, D === t && C < F.length - 1 && (e.push(""), D = 0);
30903
- }
30904
- !D && e[e.length - 1].length > 0 && e.length > 1 && (e[e.length - 2] += e.pop());
30905
- };
30906
- var hD = (e) => {
30907
- const u = e.split(" ");
30908
- let t = u.length;
30909
- for (;t > 0 && !(p(u[t - 1]) > 0); )
30910
- t--;
30911
- return t === u.length ? e : u.slice(0, t).join(" ") + u.slice(t).join("");
30912
- };
30913
- var lD = (e, u, t = {}) => {
30914
- if (t.trim !== false && e.trim() === "")
30915
- return "";
30916
- let F = "", s, i;
30917
- const D = aD(e);
30918
- let C = [""];
30919
- for (const [E, a] of e.split(" ").entries()) {
30920
- t.trim !== false && (C[C.length - 1] = C[C.length - 1].trimStart());
30921
- let o = p(C[C.length - 1]);
30922
- if (E !== 0 && (o >= u && (t.wordWrap === false || t.trim === false) && (C.push(""), o = 0), (o > 0 || t.trim === false) && (C[C.length - 1] += " ", o++)), t.hard && D[E] > u) {
30923
- const c = u - o, f = 1 + Math.floor((D[E] - c - 1) / u);
30924
- Math.floor((D[E] - 1) / u) < f && C.push(""), k(C, a, u);
30925
- continue;
30926
- }
30927
- if (o + D[E] > u && o > 0 && D[E] > 0) {
30928
- if (t.wordWrap === false && o < u) {
30929
- k(C, a, u);
30930
- continue;
30931
- }
30932
- C.push("");
30933
- }
30934
- if (o + D[E] > u && t.wordWrap === false) {
30935
- k(C, a, u);
30936
- continue;
30937
- }
30938
- C[C.length - 1] += a;
30939
- }
30940
- t.trim !== false && (C = C.map((E) => hD(E)));
30941
- const n = [...C.join(`
30942
- `)];
30943
- for (const [E, a] of n.entries()) {
30944
- if (F += a, d.has(a)) {
30945
- const { groups: c } = new RegExp(`(?:\\${V}(?<code>\\d+)m|\\${_}(?<uri>.*)${y})`).exec(n.slice(E).join("")) || { groups: {} };
30946
- if (c.code !== undefined) {
30947
- const f = Number.parseFloat(c.code);
30948
- s = f === oD ? undefined : f;
30949
- } else
30950
- c.uri !== undefined && (i = c.uri.length === 0 ? undefined : c.uri);
30951
- }
30952
- const o = ED.codes.get(Number(s));
30953
- n[E + 1] === `
30954
- ` ? (i && (F += K("")), s && o && (F += z2(o))) : a === `
30955
- ` && (s && o && (F += z2(s)), i && (F += K(i)));
30956
- }
30957
- return F;
30958
- };
30959
- function Y(e, u, t) {
30960
- return String(e).normalize().replace(/\r\n/g, `
30961
- `).split(`
30962
- `).map((F) => lD(F, u, t)).join(`
30963
- `);
30964
- }
30965
- var xD = ["up", "down", "left", "right", "space", "enter", "cancel"];
30966
- var B = { actions: new Set(xD), aliases: new Map([["k", "up"], ["j", "down"], ["h", "left"], ["l", "right"], ["\x03", "cancel"], ["escape", "cancel"]]) };
30967
- function $(e, u) {
30968
- if (typeof e == "string")
30969
- return B.aliases.get(e) === u;
30970
- for (const t of e)
30971
- if (t !== undefined && $(t, u))
30972
- return true;
30973
- return false;
30974
- }
30975
- function BD(e, u) {
30976
- if (e === u)
30977
- return;
30978
- const t = e.split(`
30979
- `), F = u.split(`
30980
- `), s = [];
30981
- for (let i = 0;i < Math.max(t.length, F.length); i++)
30982
- t[i] !== F[i] && s.push(i);
30983
- return s;
30984
- }
30985
- var AD = globalThis.process.platform.startsWith("win");
30986
- var S = Symbol("clack:cancel");
30987
- function pD(e) {
30988
- return e === S;
30989
- }
30990
- function m(e, u) {
30991
- const t = e;
30992
- t.isTTY && t.setRawMode(u);
30993
- }
30994
- function fD({ input: e = j, output: u = M, overwrite: t = true, hideCursor: F = true } = {}) {
30995
- const s = g.createInterface({ input: e, output: u, prompt: "", tabSize: 1 });
30996
- g.emitKeypressEvents(e, s), e.isTTY && e.setRawMode(true);
30997
- const i = (D, { name: C, sequence: n }) => {
30998
- const E = String(D);
30999
- if ($([E, C, n], "cancel")) {
31000
- F && u.write(import_sisteransi.cursor.show), process.exit(0);
31001
- return;
31002
- }
31003
- if (!t)
31004
- return;
31005
- const a = C === "return" ? 0 : -1, o = C === "return" ? -1 : 0;
31006
- g.moveCursor(u, a, o, () => {
31007
- g.clearLine(u, 1, () => {
31008
- e.once("keypress", i);
31009
- });
31010
- });
31011
- };
31012
- return F && u.write(import_sisteransi.cursor.hide), e.once("keypress", i), () => {
31013
- e.off("keypress", i), F && u.write(import_sisteransi.cursor.show), e.isTTY && !AD && e.setRawMode(false), s.terminal = false, s.close();
31014
- };
31015
- }
31016
- var gD = Object.defineProperty;
31017
- var vD = (e, u, t) => (u in e) ? gD(e, u, { enumerable: true, configurable: true, writable: true, value: t }) : e[u] = t;
31018
- var h = (e, u, t) => (vD(e, typeof u != "symbol" ? u + "" : u, t), t);
30769
+ Start work on a Harmony card. Card reference: $ARGUMENTS
31019
30770
 
31020
- class x {
31021
- constructor(u, t = true) {
31022
- h(this, "input"), h(this, "output"), h(this, "_abortSignal"), h(this, "rl"), h(this, "opts"), h(this, "_render"), h(this, "_track", false), h(this, "_prevFrame", ""), h(this, "_subscribers", new Map), h(this, "_cursor", 0), h(this, "state", "initial"), h(this, "error", ""), h(this, "value");
31023
- const { input: F = j, output: s = M, render: i, signal: D, ...C } = u;
31024
- this.opts = C, this.onKeypress = this.onKeypress.bind(this), this.close = this.close.bind(this), this.render = this.render.bind(this), this._render = i.bind(this), this._track = t, this._abortSignal = D, this.input = F, this.output = s;
31025
- }
31026
- unsubscribe() {
31027
- this._subscribers.clear();
31028
- }
31029
- setSubscriber(u, t) {
31030
- const F = this._subscribers.get(u) ?? [];
31031
- F.push(t), this._subscribers.set(u, F);
31032
- }
31033
- on(u, t) {
31034
- this.setSubscriber(u, { cb: t });
31035
- }
31036
- once(u, t) {
31037
- this.setSubscriber(u, { cb: t, once: true });
31038
- }
31039
- emit(u, ...t) {
31040
- const F = this._subscribers.get(u) ?? [], s = [];
31041
- for (const i of F)
31042
- i.cb(...t), i.once && s.push(() => F.splice(F.indexOf(i), 1));
31043
- for (const i of s)
31044
- i();
31045
- }
31046
- prompt() {
31047
- return new Promise((u, t) => {
31048
- if (this._abortSignal) {
31049
- if (this._abortSignal.aborted)
31050
- return this.state = "cancel", this.close(), u(S);
31051
- this._abortSignal.addEventListener("abort", () => {
31052
- this.state = "cancel", this.close();
31053
- }, { once: true });
31054
- }
31055
- const F = new X;
31056
- F._write = (s, i, D) => {
31057
- this._track && (this.value = this.rl?.line.replace(/\t/g, ""), this._cursor = this.rl?.cursor ?? 0, this.emit("value", this.value)), D();
31058
- }, this.input.pipe(F), this.rl = O.createInterface({ input: this.input, output: F, tabSize: 2, prompt: "", escapeCodeTimeout: 50, terminal: true }), O.emitKeypressEvents(this.input, this.rl), this.rl.prompt(), this.opts.initialValue !== undefined && this._track && this.rl.write(this.opts.initialValue), this.input.on("keypress", this.onKeypress), m(this.input, true), this.output.on("resize", this.render), this.render(), this.once("submit", () => {
31059
- this.output.write(import_sisteransi.cursor.show), this.output.off("resize", this.render), m(this.input, false), u(this.value);
31060
- }), this.once("cancel", () => {
31061
- this.output.write(import_sisteransi.cursor.show), this.output.off("resize", this.render), m(this.input, false), u(S);
31062
- });
31063
- });
31064
- }
31065
- onKeypress(u, t) {
31066
- if (this.state === "error" && (this.state = "active"), t?.name && (!this._track && B.aliases.has(t.name) && this.emit("cursor", B.aliases.get(t.name)), B.actions.has(t.name) && this.emit("cursor", t.name)), u && (u.toLowerCase() === "y" || u.toLowerCase() === "n") && this.emit("confirm", u.toLowerCase() === "y"), u === "\t" && this.opts.placeholder && (this.value || (this.rl?.write(this.opts.placeholder), this.emit("value", this.opts.placeholder))), u && this.emit("key", u.toLowerCase()), t?.name === "return") {
31067
- if (this.opts.validate) {
31068
- const F = this.opts.validate(this.value);
31069
- F && (this.error = F instanceof Error ? F.message : F, this.state = "error", this.rl?.write(this.value));
31070
- }
31071
- this.state !== "error" && (this.state = "submit");
31072
- }
31073
- $([u, t?.name, t?.sequence], "cancel") && (this.state = "cancel"), (this.state === "submit" || this.state === "cancel") && this.emit("finalize"), this.render(), (this.state === "submit" || this.state === "cancel") && this.close();
31074
- }
31075
- close() {
31076
- this.input.unpipe(), this.input.removeListener("keypress", this.onKeypress), this.output.write(`
31077
- `), m(this.input, false), this.rl?.close(), this.rl = undefined, this.emit(`${this.state}`, this.value), this.unsubscribe();
31078
- }
31079
- restoreCursor() {
31080
- const u = Y(this._prevFrame, process.stdout.columns, { hard: true }).split(`
31081
- `).length - 1;
31082
- this.output.write(import_sisteransi.cursor.move(-999, u * -1));
31083
- }
31084
- render() {
31085
- const u = Y(this._render(this) ?? "", process.stdout.columns, { hard: true });
31086
- if (u !== this._prevFrame) {
31087
- if (this.state === "initial")
31088
- this.output.write(import_sisteransi.cursor.hide);
31089
- else {
31090
- const t = BD(this._prevFrame, u);
31091
- if (this.restoreCursor(), t && t?.length === 1) {
31092
- const F = t[0];
31093
- this.output.write(import_sisteransi.cursor.move(0, F)), this.output.write(import_sisteransi.erase.lines(1));
31094
- const s = u.split(`
31095
- `);
31096
- this.output.write(s[F]), this._prevFrame = u, this.output.write(import_sisteransi.cursor.move(0, s.length - F - 1));
31097
- return;
31098
- }
31099
- if (t && t?.length > 1) {
31100
- const F = t[0];
31101
- this.output.write(import_sisteransi.cursor.move(0, F)), this.output.write(import_sisteransi.erase.down());
31102
- const s = u.split(`
31103
- `).slice(F);
31104
- this.output.write(s.join(`
31105
- `)), this._prevFrame = u;
31106
- return;
31107
- }
31108
- this.output.write(import_sisteransi.erase.down());
31109
- }
31110
- this.output.write(u), this.state === "initial" && (this.state = "active"), this._prevFrame = u;
31111
- }
31112
- }
31113
- }
30771
+ ## 1. Find & Fetch Card
31114
30772
 
31115
- class dD extends x {
31116
- get cursor() {
31117
- return this.value ? 0 : 1;
31118
- }
31119
- get _value() {
31120
- return this.cursor === 0;
31121
- }
31122
- constructor(u) {
31123
- super(u, false), this.value = !!u.initialValue, this.on("value", () => {
31124
- this.value = this._value;
31125
- }), this.on("confirm", (t) => {
31126
- this.output.write(import_sisteransi.cursor.move(0, -1)), this.value = t, this.state = "submit", this.close();
31127
- }), this.on("cursor", () => {
31128
- this.value = !this.value;
31129
- });
31130
- }
31131
- }
31132
- var A;
31133
- A = new WeakMap;
31134
- var kD = Object.defineProperty;
31135
- var $D = (e, u, t) => (u in e) ? kD(e, u, { enumerable: true, configurable: true, writable: true, value: t }) : e[u] = t;
31136
- var H = (e, u, t) => ($D(e, typeof u != "symbol" ? u + "" : u, t), t);
31137
- var SD = class extends x {
31138
- constructor(u) {
31139
- super(u, false), H(this, "options"), H(this, "cursor", 0), this.options = u.options, this.value = [...u.initialValues ?? []], this.cursor = Math.max(this.options.findIndex(({ value: t }) => t === u.cursorAt), 0), this.on("key", (t) => {
31140
- t === "a" && this.toggleAll();
31141
- }), this.on("cursor", (t) => {
31142
- switch (t) {
31143
- case "left":
31144
- case "up":
31145
- this.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1;
31146
- break;
31147
- case "down":
31148
- case "right":
31149
- this.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1;
31150
- break;
31151
- case "space":
31152
- this.toggleValue();
31153
- break;
31154
- }
31155
- });
31156
- }
31157
- get _value() {
31158
- return this.options[this.cursor].value;
31159
- }
31160
- toggleAll() {
31161
- const u = this.value.length === this.options.length;
31162
- this.value = u ? [] : this.options.map((t) => t.value);
31163
- }
31164
- toggleValue() {
31165
- const u = this.value.includes(this._value);
31166
- this.value = u ? this.value.filter((t) => t !== this._value) : [...this.value, this._value];
31167
- }
31168
- };
31169
- var OD = Object.defineProperty;
31170
- var PD = (e, u, t) => (u in e) ? OD(e, u, { enumerable: true, configurable: true, writable: true, value: t }) : e[u] = t;
31171
- var J = (e, u, t) => (PD(e, typeof u != "symbol" ? u + "" : u, t), t);
30773
+ Parse the reference and fetch the card:
30774
+ - \`#42\` or \`42\` → \`harmony_get_card_by_short_id\` with \`shortId: 42\`
30775
+ - UUID \`harmony_get_card\` with \`cardId\`
30776
+ - Name/text → \`harmony_search_cards\` with \`query\`
31172
30777
 
31173
- class LD extends x {
31174
- constructor(u) {
31175
- super(u, false), J(this, "options"), J(this, "cursor", 0), this.options = u.options, this.cursor = this.options.findIndex(({ value: t }) => t === u.initialValue), this.cursor === -1 && (this.cursor = 0), this.changeValue(), this.on("cursor", (t) => {
31176
- switch (t) {
31177
- case "left":
31178
- case "up":
31179
- this.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1;
31180
- break;
31181
- case "down":
31182
- case "right":
31183
- this.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1;
31184
- break;
31185
- }
31186
- this.changeValue();
31187
- });
31188
- }
31189
- get _value() {
31190
- return this.options[this.cursor];
31191
- }
31192
- changeValue() {
31193
- this.value = this._value.value;
31194
- }
31195
- }
31196
- class RD extends x {
31197
- get valueWithCursor() {
31198
- if (this.state === "submit")
31199
- return this.value;
31200
- if (this.cursor >= this.value.length)
31201
- return `${this.value}█`;
31202
- const u = this.value.slice(0, this.cursor), [t, ...F] = this.value.slice(this.cursor);
31203
- return `${u}${import_picocolors.default.inverse(t)}${F.join("")}`;
31204
- }
31205
- get cursor() {
31206
- return this._cursor;
31207
- }
31208
- constructor(u) {
31209
- super(u), this.on("finalize", () => {
31210
- this.value || (this.value = u.defaultValue);
31211
- });
31212
- }
31213
- }
30778
+ ## 2. Get Board State
31214
30779
 
31215
- // ../../node_modules/@clack/prompts/dist/index.mjs
31216
- var import_picocolors2 = __toESM(require_picocolors(), 1);
31217
- var import_sisteransi2 = __toESM(require_src(), 1);
31218
- import y2 from "node:process";
31219
- function ce() {
31220
- return y2.platform !== "win32" ? y2.env.TERM !== "linux" : !!y2.env.CI || !!y2.env.WT_SESSION || !!y2.env.TERMINUS_SUBLIME || y2.env.ConEmuTask === "{cmd::Cmder}" || y2.env.TERM_PROGRAM === "Terminus-Sublime" || y2.env.TERM_PROGRAM === "vscode" || y2.env.TERM === "xterm-256color" || y2.env.TERM === "alacritty" || y2.env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
31221
- }
31222
- var V2 = ce();
31223
- var u = (t, n) => V2 ? t : n;
31224
- var le = u("◆", "*");
31225
- var L2 = u("■", "x");
31226
- var W2 = u("▲", "x");
31227
- var C = u("◇", "o");
31228
- var ue = u("┌", "T");
31229
- var o = u("│", "|");
31230
- var d2 = u("└", "—");
31231
- var k2 = u("●", ">");
31232
- var P2 = u("○", " ");
31233
- var A2 = u("◻", "[•]");
31234
- var T = u("◼", "[+]");
31235
- var F = u("◻", "[ ]");
31236
- var $e = u("▪", "•");
31237
- var _2 = u("─", "-");
31238
- var me = u("╮", "+");
31239
- var de = u("├", "+");
31240
- var pe = u("╯", "+");
31241
- var q = u("●", "•");
31242
- var D = u("◆", "*");
31243
- var U = u("▲", "!");
31244
- var K2 = u("■", "x");
31245
- var b2 = (t) => {
31246
- switch (t) {
31247
- case "initial":
31248
- case "active":
31249
- return import_picocolors2.default.cyan(le);
31250
- case "cancel":
31251
- return import_picocolors2.default.red(L2);
31252
- case "error":
31253
- return import_picocolors2.default.yellow(W2);
31254
- case "submit":
31255
- return import_picocolors2.default.green(C);
31256
- }
31257
- };
31258
- var G2 = (t) => {
31259
- const { cursor: n, options: r2, style: i } = t, s = t.maxItems ?? Number.POSITIVE_INFINITY, c = Math.max(process.stdout.rows - 4, 0), a = Math.min(c, Math.max(s, 5));
31260
- let l2 = 0;
31261
- n >= l2 + a - 3 ? l2 = Math.max(Math.min(n - a + 3, r2.length - a), 0) : n < l2 + 2 && (l2 = Math.max(n - 2, 0));
31262
- const $2 = a < r2.length && l2 > 0, g2 = a < r2.length && l2 + a < r2.length;
31263
- return r2.slice(l2, l2 + a).map((p2, v2, f) => {
31264
- const j2 = v2 === 0 && $2, E = v2 === f.length - 1 && g2;
31265
- return j2 || E ? import_picocolors2.default.dim("...") : i(p2, v2 + l2 === n);
31266
- });
31267
- };
31268
- var he = (t) => new RD({ validate: t.validate, placeholder: t.placeholder, defaultValue: t.defaultValue, initialValue: t.initialValue, render() {
31269
- const n = `${import_picocolors2.default.gray(o)}
31270
- ${b2(this.state)} ${t.message}
31271
- `, r2 = t.placeholder ? import_picocolors2.default.inverse(t.placeholder[0]) + import_picocolors2.default.dim(t.placeholder.slice(1)) : import_picocolors2.default.inverse(import_picocolors2.default.hidden("_")), i = this.value ? this.valueWithCursor : r2;
31272
- switch (this.state) {
31273
- case "error":
31274
- return `${n.trim()}
31275
- ${import_picocolors2.default.yellow(o)} ${i}
31276
- ${import_picocolors2.default.yellow(d2)} ${import_picocolors2.default.yellow(this.error)}
31277
- `;
31278
- case "submit":
31279
- return `${n}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.dim(this.value || t.placeholder)}`;
31280
- case "cancel":
31281
- return `${n}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(this.value ?? ""))}${this.value?.trim() ? `
31282
- ${import_picocolors2.default.gray(o)}` : ""}`;
31283
- default:
31284
- return `${n}${import_picocolors2.default.cyan(o)} ${i}
31285
- ${import_picocolors2.default.cyan(d2)}
31286
- `;
31287
- }
31288
- } }).prompt();
31289
- var ye = (t) => {
31290
- const n = t.active ?? "Yes", r2 = t.inactive ?? "No";
31291
- return new dD({ active: n, inactive: r2, initialValue: t.initialValue ?? true, render() {
31292
- const i = `${import_picocolors2.default.gray(o)}
31293
- ${b2(this.state)} ${t.message}
31294
- `, s = this.value ? n : r2;
31295
- switch (this.state) {
31296
- case "submit":
31297
- return `${i}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.dim(s)}`;
31298
- case "cancel":
31299
- return `${i}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(s))}
31300
- ${import_picocolors2.default.gray(o)}`;
31301
- default:
31302
- return `${i}${import_picocolors2.default.cyan(o)} ${this.value ? `${import_picocolors2.default.green(k2)} ${n}` : `${import_picocolors2.default.dim(P2)} ${import_picocolors2.default.dim(n)}`} ${import_picocolors2.default.dim("/")} ${this.value ? `${import_picocolors2.default.dim(P2)} ${import_picocolors2.default.dim(r2)}` : `${import_picocolors2.default.green(k2)} ${r2}`}
31303
- ${import_picocolors2.default.cyan(d2)}
31304
- `;
31305
- }
31306
- } }).prompt();
31307
- };
31308
- var ve = (t) => {
31309
- const n = (r2, i) => {
31310
- const s = r2.label ?? String(r2.value);
31311
- switch (i) {
31312
- case "selected":
31313
- return `${import_picocolors2.default.dim(s)}`;
31314
- case "active":
31315
- return `${import_picocolors2.default.green(k2)} ${s} ${r2.hint ? import_picocolors2.default.dim(`(${r2.hint})`) : ""}`;
31316
- case "cancelled":
31317
- return `${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(s))}`;
31318
- default:
31319
- return `${import_picocolors2.default.dim(P2)} ${import_picocolors2.default.dim(s)}`;
31320
- }
31321
- };
31322
- return new LD({ options: t.options, initialValue: t.initialValue, render() {
31323
- const r2 = `${import_picocolors2.default.gray(o)}
31324
- ${b2(this.state)} ${t.message}
31325
- `;
31326
- switch (this.state) {
31327
- case "submit":
31328
- return `${r2}${import_picocolors2.default.gray(o)} ${n(this.options[this.cursor], "selected")}`;
31329
- case "cancel":
31330
- return `${r2}${import_picocolors2.default.gray(o)} ${n(this.options[this.cursor], "cancelled")}
31331
- ${import_picocolors2.default.gray(o)}`;
31332
- default:
31333
- return `${r2}${import_picocolors2.default.cyan(o)} ${G2({ cursor: this.cursor, options: this.options, maxItems: t.maxItems, style: (i, s) => n(i, s ? "active" : "inactive") }).join(`
31334
- ${import_picocolors2.default.cyan(o)} `)}
31335
- ${import_picocolors2.default.cyan(d2)}
31336
- `;
31337
- }
31338
- } }).prompt();
31339
- };
31340
- var fe = (t) => {
31341
- const n = (r2, i) => {
31342
- const s = r2.label ?? String(r2.value);
31343
- return i === "active" ? `${import_picocolors2.default.cyan(A2)} ${s} ${r2.hint ? import_picocolors2.default.dim(`(${r2.hint})`) : ""}` : i === "selected" ? `${import_picocolors2.default.green(T)} ${import_picocolors2.default.dim(s)} ${r2.hint ? import_picocolors2.default.dim(`(${r2.hint})`) : ""}` : i === "cancelled" ? `${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(s))}` : i === "active-selected" ? `${import_picocolors2.default.green(T)} ${s} ${r2.hint ? import_picocolors2.default.dim(`(${r2.hint})`) : ""}` : i === "submitted" ? `${import_picocolors2.default.dim(s)}` : `${import_picocolors2.default.dim(F)} ${import_picocolors2.default.dim(s)}`;
31344
- };
31345
- return new SD({ options: t.options, initialValues: t.initialValues, required: t.required ?? true, cursorAt: t.cursorAt, validate(r2) {
31346
- if (this.required && r2.length === 0)
31347
- return `Please select at least one option.
31348
- ${import_picocolors2.default.reset(import_picocolors2.default.dim(`Press ${import_picocolors2.default.gray(import_picocolors2.default.bgWhite(import_picocolors2.default.inverse(" space ")))} to select, ${import_picocolors2.default.gray(import_picocolors2.default.bgWhite(import_picocolors2.default.inverse(" enter ")))} to submit`))}`;
31349
- }, render() {
31350
- const r2 = `${import_picocolors2.default.gray(o)}
31351
- ${b2(this.state)} ${t.message}
31352
- `, i = (s, c) => {
31353
- const a = this.value.includes(s.value);
31354
- return c && a ? n(s, "active-selected") : a ? n(s, "selected") : n(s, c ? "active" : "inactive");
31355
- };
31356
- switch (this.state) {
31357
- case "submit":
31358
- return `${r2}${import_picocolors2.default.gray(o)} ${this.options.filter(({ value: s }) => this.value.includes(s)).map((s) => n(s, "submitted")).join(import_picocolors2.default.dim(", ")) || import_picocolors2.default.dim("none")}`;
31359
- case "cancel": {
31360
- const s = this.options.filter(({ value: c }) => this.value.includes(c)).map((c) => n(c, "cancelled")).join(import_picocolors2.default.dim(", "));
31361
- return `${r2}${import_picocolors2.default.gray(o)} ${s.trim() ? `${s}
31362
- ${import_picocolors2.default.gray(o)}` : ""}`;
31363
- }
31364
- case "error": {
31365
- const s = this.error.split(`
31366
- `).map((c, a) => a === 0 ? `${import_picocolors2.default.yellow(d2)} ${import_picocolors2.default.yellow(c)}` : ` ${c}`).join(`
31367
- `);
31368
- return `${r2 + import_picocolors2.default.yellow(o)} ${G2({ options: this.options, cursor: this.cursor, maxItems: t.maxItems, style: i }).join(`
31369
- ${import_picocolors2.default.yellow(o)} `)}
31370
- ${s}
31371
- `;
31372
- }
31373
- default:
31374
- return `${r2}${import_picocolors2.default.cyan(o)} ${G2({ options: this.options, cursor: this.cursor, maxItems: t.maxItems, style: i }).join(`
31375
- ${import_picocolors2.default.cyan(o)} `)}
31376
- ${import_picocolors2.default.cyan(d2)}
31377
- `;
31378
- }
31379
- } }).prompt();
31380
- };
31381
- var xe = (t = "") => {
31382
- process.stdout.write(`${import_picocolors2.default.gray(d2)} ${import_picocolors2.default.red(t)}
30780
+ Call \`harmony_get_board\` to get columns and labels. From the response:
30781
+ - Find the "In Progress" (or "Progress") column ID
30782
+ - Find the "agent" label ID
31383
30783
 
31384
- `);
31385
- };
31386
- var Se = (t = "") => {
31387
- process.stdout.write(`${import_picocolors2.default.gray(o)}
31388
- ${import_picocolors2.default.gray(d2)} ${t}
30784
+ ## 3. Setup Card for Work
31389
30785
 
31390
- `);
31391
- };
31392
- var M2 = { message: (t = "", { symbol: n = import_picocolors2.default.gray(o) } = {}) => {
31393
- const r2 = [`${import_picocolors2.default.gray(o)}`];
31394
- if (t) {
31395
- const [i, ...s] = t.split(`
31396
- `);
31397
- r2.push(`${n} ${i}`, ...s.map((c) => `${import_picocolors2.default.gray(o)} ${c}`));
31398
- }
31399
- process.stdout.write(`${r2.join(`
31400
- `)}
31401
- `);
31402
- }, info: (t) => {
31403
- M2.message(t, { symbol: import_picocolors2.default.blue(q) });
31404
- }, success: (t) => {
31405
- M2.message(t, { symbol: import_picocolors2.default.green(D) });
31406
- }, step: (t) => {
31407
- M2.message(t, { symbol: import_picocolors2.default.green(C) });
31408
- }, warn: (t) => {
31409
- M2.message(t, { symbol: import_picocolors2.default.yellow(U) });
31410
- }, warning: (t) => {
31411
- M2.warn(t);
31412
- }, error: (t) => {
31413
- M2.message(t, { symbol: import_picocolors2.default.red(K2) });
31414
- } };
31415
- var J2 = `${import_picocolors2.default.gray(o)} `;
31416
- var Y2 = ({ indicator: t = "dots" } = {}) => {
31417
- const n = V2 ? ["◒", "◐", "◓", "◑"] : ["•", "o", "O", "0"], r2 = V2 ? 80 : 120, i = process.env.CI === "true";
31418
- let s, c, a = false, l2 = "", $2, g2 = performance.now();
31419
- const p2 = (m2) => {
31420
- const h2 = m2 > 1 ? "Something went wrong" : "Canceled";
31421
- a && N2(h2, m2);
31422
- }, v2 = () => p2(2), f = () => p2(1), j2 = () => {
31423
- process.on("uncaughtExceptionMonitor", v2), process.on("unhandledRejection", v2), process.on("SIGINT", f), process.on("SIGTERM", f), process.on("exit", p2);
31424
- }, E = () => {
31425
- process.removeListener("uncaughtExceptionMonitor", v2), process.removeListener("unhandledRejection", v2), process.removeListener("SIGINT", f), process.removeListener("SIGTERM", f), process.removeListener("exit", p2);
31426
- }, B2 = () => {
31427
- if ($2 === undefined)
31428
- return;
31429
- i && process.stdout.write(`
31430
- `);
31431
- const m2 = $2.split(`
31432
- `);
31433
- process.stdout.write(import_sisteransi2.cursor.move(-999, m2.length - 1)), process.stdout.write(import_sisteransi2.erase.down(m2.length));
31434
- }, R2 = (m2) => m2.replace(/\.+$/, ""), O2 = (m2) => {
31435
- const h2 = (performance.now() - m2) / 1000, w2 = Math.floor(h2 / 60), I2 = Math.floor(h2 % 60);
31436
- return w2 > 0 ? `[${w2}m ${I2}s]` : `[${I2}s]`;
31437
- }, H2 = (m2 = "") => {
31438
- a = true, s = fD(), l2 = R2(m2), g2 = performance.now(), process.stdout.write(`${import_picocolors2.default.gray(o)}
31439
- `);
31440
- let h2 = 0, w2 = 0;
31441
- j2(), c = setInterval(() => {
31442
- if (i && l2 === $2)
31443
- return;
31444
- B2(), $2 = l2;
31445
- const I2 = import_picocolors2.default.magenta(n[h2]);
31446
- if (i)
31447
- process.stdout.write(`${I2} ${l2}...`);
31448
- else if (t === "timer")
31449
- process.stdout.write(`${I2} ${l2} ${O2(g2)}`);
31450
- else {
31451
- const z3 = ".".repeat(Math.floor(w2)).slice(0, 3);
31452
- process.stdout.write(`${I2} ${l2}${z3}`);
31453
- }
31454
- h2 = h2 + 1 < n.length ? h2 + 1 : 0, w2 = w2 < n.length ? w2 + 0.125 : 0;
31455
- }, r2);
31456
- }, N2 = (m2 = "", h2 = 0) => {
31457
- a = false, clearInterval(c), B2();
31458
- const w2 = h2 === 0 ? import_picocolors2.default.green(C) : h2 === 1 ? import_picocolors2.default.red(L2) : import_picocolors2.default.red(W2);
31459
- l2 = R2(m2 ?? l2), t === "timer" ? process.stdout.write(`${w2} ${l2} ${O2(g2)}
31460
- `) : process.stdout.write(`${w2} ${l2}
31461
- `), E(), s();
31462
- };
31463
- return { start: H2, stop: N2, message: (m2 = "") => {
31464
- l2 = R2(m2 ?? l2);
31465
- } };
31466
- };
30786
+ Execute these in sequence:
30787
+ 1. \`harmony_move_card\` → Move to "In Progress" column
30788
+ 2. \`harmony_add_label_to_card\` Add "agent" label
30789
+ 3. \`harmony_start_agent_session\`:
30790
+ - \`cardId\`: Card UUID
30791
+ - \`agentIdentifier\`: Your agent identifier
30792
+ - \`agentName\`: Your agent name
30793
+ - \`currentTask\`: "Analyzing card requirements"
31467
30794
 
31468
- // src/tui/agents.ts
31469
- import { existsSync as existsSync3 } from "node:fs";
31470
- import { homedir as homedir2 } from "node:os";
31471
- import { join as join3 } from "node:path";
31472
- var AGENT_DEFINITIONS = [
31473
- {
31474
- id: "claude",
31475
- name: "Claude Code",
31476
- description: "Anthropic CLI agent",
31477
- hint: "/hmy <card>",
31478
- globalPaths: [join3(homedir2(), ".claude")],
31479
- localPaths: [".claude"]
31480
- },
31481
- {
31482
- id: "codex",
31483
- name: "Codex",
31484
- description: "OpenAI coding agent",
31485
- hint: "/prompts:hmy <card>",
31486
- globalPaths: [join3(homedir2(), ".codex")],
31487
- localPaths: ["AGENTS.md"]
31488
- },
31489
- {
31490
- id: "cursor",
31491
- name: "Cursor",
31492
- description: "AI-powered IDE",
31493
- hint: "MCP tools available automatically",
31494
- globalPaths: [],
31495
- localPaths: [".cursor", ".cursorrules"]
31496
- },
31497
- {
31498
- id: "windsurf",
31499
- name: "Windsurf",
31500
- description: "Codeium AI IDE",
31501
- hint: "MCP tools available automatically",
31502
- globalPaths: [join3(homedir2(), ".codeium", "windsurf")],
31503
- localPaths: [".windsurf", ".windsurfrules"]
31504
- }
31505
- ];
31506
- function detectAgents(cwd = process.cwd()) {
31507
- return AGENT_DEFINITIONS.map((def) => {
31508
- const globalPath = def.globalPaths.find((p2) => existsSync3(p2)) || null;
31509
- const localPath = def.localPaths.find((p2) => existsSync3(join3(cwd, p2))) || null;
31510
- return {
31511
- id: def.id,
31512
- name: def.name,
31513
- detected: !!(globalPath || localPath),
31514
- globalPath,
31515
- localPath: localPath ? join3(cwd, localPath) : null,
31516
- description: def.description,
31517
- hint: def.hint
31518
- };
31519
- });
31520
- }
30795
+ ## 4. Generate Work Prompt
31521
30796
 
31522
- // src/tui/docs.ts
31523
- import {
31524
- existsSync as existsSync4,
31525
- readFileSync as readFileSync3,
31526
- readdirSync as readdirSync2,
31527
- statSync
31528
- } from "node:fs";
31529
- import { join as join4 } from "node:path";
30797
+ Call \`harmony_generate_prompt\` with:
30798
+ - \`cardId\` or \`shortId\` (+ \`projectId\` if using shortId)
30799
+ - \`variant\`: Select based on task:
30800
+ - \`"execute"\` (default) → Clear tasks, bug fixes, well-defined work
30801
+ - \`"analysis"\` → Complex features, unclear requirements
30802
+ - \`"draft"\` → Medium complexity, want feedback first
31530
30803
 
31531
- // src/tui/theme.ts
31532
- var pc = __toESM(require_picocolors(), 1);
31533
- var symbols = {
31534
- harmony: "▲",
31535
- check: "✓",
31536
- cross: "✗",
31537
- bullet: "•",
31538
- arrow: "→",
31539
- arrowRight: "▸",
31540
- dot: "●",
31541
- dotEmpty: "○",
31542
- info: "ℹ",
31543
- warning: "⚠",
31544
- pointer: "❯"
31545
- };
31546
- var colors = {
31547
- brand: (text) => pc.cyan(text),
31548
- brandBold: (text) => pc.bold(pc.cyan(text)),
31549
- success: (text) => pc.green(text),
31550
- error: (text) => pc.red(text),
31551
- warning: (text) => pc.yellow(text),
31552
- info: (text) => pc.blue(text),
31553
- dim: (text) => pc.dim(text),
31554
- bold: (text) => pc.bold(text),
31555
- muted: (text) => pc.gray(text),
31556
- highlight: (text) => pc.cyan(text),
31557
- link: (text) => pc.underline(pc.cyan(text))
31558
- };
31559
- var messages = {
31560
- header: () => {
31561
- return `
31562
- ${colors.brandBold(" HARMONY")}
31563
- ${colors.dim(" Project management for AI agents")}
30804
+ The generated prompt provides role framing, focus areas, subtasks, linked cards, and suggested outputs.
30805
+
30806
+ ## 5. Display Card Summary
30807
+
30808
+ Show the user: Card title, short ID, role, priority, labels, due date, description, and subtasks.
30809
+
30810
+ ## 6. Implement Solution
30811
+
30812
+ Work on the card following the generated prompt's guidance. Update progress at milestones:
30813
+ - \`harmony_update_agent_progress\` with \`progressPercent\` (0-100), \`currentTask\`, \`status\`, \`blockers\`
30814
+
30815
+ **Progress checkpoints:** 20% (exploration), 50% (implementation), 80% (testing), 100% (done)
30816
+
30817
+ ## 7. Complete Work
30818
+
30819
+ When finished:
30820
+ 1. \`harmony_end_agent_session\` with \`status: "completed"\`, \`progressPercent: 100\`
30821
+ 2. \`harmony_move_card\` to "Review" column
30822
+ 3. Summarize accomplishments
30823
+
30824
+ If pausing: \`harmony_end_agent_session\` with \`status: "paused"\`
30825
+
30826
+ ## Key Tools Reference
30827
+
30828
+ **Cards:** \`harmony_get_card\`, \`harmony_get_card_by_short_id\`, \`harmony_search_cards\`, \`harmony_create_card\`, \`harmony_update_card\`, \`harmony_move_card\`, \`harmony_delete_card\`, \`harmony_assign_card\`
30829
+
30830
+ **Subtasks:** \`harmony_create_subtask\`, \`harmony_toggle_subtask\`, \`harmony_delete_subtask\`
30831
+
30832
+ **Labels:** \`harmony_add_label_to_card\`, \`harmony_remove_label_from_card\`, \`harmony_create_label\`
30833
+
30834
+ **Links:** \`harmony_add_link_to_card\`, \`harmony_remove_link_from_card\`, \`harmony_get_card_links\`
30835
+
30836
+ **Board:** \`harmony_get_board\`, \`harmony_list_projects\`, \`harmony_get_context\`, \`harmony_set_project_context\`
30837
+
30838
+ **Sessions:** \`harmony_start_agent_session\`, \`harmony_update_agent_progress\`, \`harmony_end_agent_session\`, \`harmony_get_agent_session\`
30839
+
30840
+ **AI:** \`harmony_generate_prompt\`, \`harmony_process_command\`
31564
30841
  `;
31565
- },
31566
- done: (message) => {
31567
- return `${colors.success(symbols.check)} ${message}`;
31568
- },
31569
- fail: (message) => {
31570
- return `${colors.error(symbols.cross)} ${message}`;
31571
- },
31572
- skip: (message) => {
31573
- return `${colors.dim("-")} ${colors.dim(message)}`;
31574
- },
31575
- step: (number5, total, message) => {
31576
- return `${colors.dim(`[${number5}/${total}]`)} ${message}`;
31577
- },
31578
- fileCreated: (path) => {
31579
- return ` ${colors.success(symbols.check)} ${colors.dim(path)}`;
31580
- },
31581
- fileSkipped: (path) => {
31582
- return ` ${colors.dim(symbols.bullet)} ${colors.dim(path)} ${colors.dim("(exists)")}`;
31583
- },
31584
- fileError: (path, error48) => {
31585
- return ` ${colors.error(symbols.cross)} ${path}: ${colors.error(error48)}`;
31586
- }
31587
- };
31588
- function formatPath(path, homeDir) {
31589
- if (path.startsWith(homeDir)) {
31590
- return `~${path.slice(homeDir.length)}`;
31591
- }
31592
- return path;
31593
- }
30842
+ var HMY_SKILL_CONTENT = `# Harmony Card Workflow
31594
30843
 
31595
- // src/tui/docs.ts
31596
- var IGNORED_DIRS = new Set([
31597
- "node_modules",
31598
- ".git",
31599
- "dist",
31600
- "build",
31601
- ".next",
31602
- ".nuxt",
31603
- ".output",
31604
- ".vercel",
31605
- ".turbo",
31606
- ".cache",
31607
- "coverage",
31608
- ".harmony-worktrees",
31609
- "__pycache__",
31610
- "target",
31611
- "vendor"
31612
- ]);
31613
- function readJson(filePath) {
31614
- try {
31615
- return JSON.parse(readFileSync3(filePath, "utf-8"));
31616
- } catch {
31617
- return null;
31618
- }
31619
- }
31620
- function readText(filePath) {
31621
- try {
31622
- return readFileSync3(filePath, "utf-8");
31623
- } catch {
31624
- return null;
31625
- }
31626
- }
31627
- function listDirs(dirPath) {
31628
- try {
31629
- return readdirSync2(dirPath).filter((entry) => {
31630
- if (IGNORED_DIRS.has(entry) || entry.startsWith("."))
31631
- return false;
31632
- try {
31633
- return statSync(join4(dirPath, entry)).isDirectory();
31634
- } catch {
31635
- return false;
31636
- }
31637
- });
31638
- } catch {
31639
- return [];
31640
- }
31641
- }
31642
- var DIR_DESCRIPTIONS = {
31643
- components: "UI components",
31644
- pages: "Route-level pages",
31645
- routes: "Route-level pages",
31646
- views: "Route-level pages",
31647
- hooks: "Custom hooks",
31648
- lib: "Utilities",
31649
- utils: "Utilities",
31650
- api: "API / server code",
31651
- server: "API / server code",
31652
- contexts: "State management",
31653
- store: "State management",
31654
- stores: "State management",
31655
- types: "Type definitions",
31656
- styles: "Stylesheets",
31657
- public: "Static assets",
31658
- static: "Static assets",
31659
- assets: "Static assets",
31660
- supabase: "Supabase backend",
31661
- functions: "Edge functions",
31662
- packages: "Monorepo packages",
31663
- apps: "Monorepo applications",
31664
- src: "Source code",
31665
- test: "Tests",
31666
- tests: "Tests",
31667
- __tests__: "Tests",
31668
- scripts: "Build / utility scripts",
31669
- config: "Configuration",
31670
- docs: "Documentation",
31671
- migrations: "Database migrations",
31672
- prisma: "Prisma schema & migrations",
31673
- e2e: "End-to-end tests",
31674
- cypress: "Cypress tests"
31675
- };
31676
- function describeDir(name) {
31677
- return DIR_DESCRIPTIONS[name.toLowerCase()] ?? name;
31678
- }
31679
- function scanProject(cwd) {
31680
- let packageManager = null;
31681
- if (existsSync4(join4(cwd, "bun.lock")) || existsSync4(join4(cwd, "bun.lockb"))) {
31682
- packageManager = "bun";
31683
- } else if (existsSync4(join4(cwd, "pnpm-lock.yaml"))) {
31684
- packageManager = "pnpm";
31685
- } else if (existsSync4(join4(cwd, "yarn.lock"))) {
31686
- packageManager = "yarn";
31687
- } else if (existsSync4(join4(cwd, "package.json"))) {
31688
- packageManager = "npm";
31689
- }
31690
- const pkg = readJson(join4(cwd, "package.json"));
31691
- const scripts = pkg && typeof pkg.scripts === "object" && pkg.scripts !== null ? pkg.scripts : {};
31692
- let language = "unknown";
31693
- if (existsSync4(join4(cwd, "tsconfig.json"))) {
31694
- language = "typescript";
31695
- } else if (existsSync4(join4(cwd, "go.mod"))) {
31696
- language = "go";
31697
- } else if (existsSync4(join4(cwd, "Cargo.toml"))) {
31698
- language = "rust";
31699
- } else if (existsSync4(join4(cwd, "setup.py")) || existsSync4(join4(cwd, "pyproject.toml"))) {
31700
- language = "python";
31701
- } else if (pkg) {
31702
- language = "javascript";
31703
- }
31704
- let framework = null;
31705
- if (pkg) {
31706
- const deps = {
31707
- ...typeof pkg.dependencies === "object" ? pkg.dependencies : {},
31708
- ...typeof pkg.devDependencies === "object" ? pkg.devDependencies : {}
31709
- };
31710
- if (deps.next) {
31711
- framework = "next";
31712
- } else if (deps.react && deps.vite) {
31713
- framework = "react+vite";
31714
- } else if (deps.react) {
31715
- framework = "react";
31716
- } else if (deps.vue && deps.vite) {
31717
- framework = "vue+vite";
31718
- } else if (deps.vue && deps.nuxt) {
31719
- framework = "nuxt";
31720
- } else if (deps.vue) {
31721
- framework = "vue";
31722
- } else if (deps.astro) {
31723
- framework = "astro";
31724
- } else if (deps.svelte) {
31725
- framework = "svelte";
31726
- } else if (deps.express) {
31727
- framework = "express";
31728
- } else if (deps.fastify) {
31729
- framework = "fastify";
31730
- } else if (deps.hono) {
31731
- framework = "hono";
31732
- }
31733
- }
31734
- let linter = null;
31735
- if (existsSync4(join4(cwd, "biome.json")) || existsSync4(join4(cwd, "biome.jsonc"))) {
31736
- linter = "biome";
31737
- } else {
31738
- const eslintFiles = [
31739
- ".eslintrc",
31740
- ".eslintrc.js",
31741
- ".eslintrc.cjs",
31742
- ".eslintrc.json",
31743
- ".eslintrc.yml",
31744
- ".eslintrc.yaml",
31745
- "eslint.config.js",
31746
- "eslint.config.mjs",
31747
- "eslint.config.cjs",
31748
- "eslint.config.ts"
31749
- ];
31750
- if (eslintFiles.some((f) => existsSync4(join4(cwd, f)))) {
31751
- linter = "eslint";
31752
- } else {
31753
- const prettierFiles = [
31754
- ".prettierrc",
31755
- ".prettierrc.js",
31756
- ".prettierrc.json",
31757
- ".prettierrc.yml",
31758
- ".prettierrc.yaml",
31759
- "prettier.config.js",
31760
- "prettier.config.mjs"
31761
- ];
31762
- if (prettierFiles.some((f) => existsSync4(join4(cwd, f)))) {
31763
- linter = "prettier";
31764
- }
31765
- }
31766
- }
31767
- let indentStyle = null;
31768
- const biome = readJson(join4(cwd, "biome.json")) ?? readJson(join4(cwd, "biome.jsonc"));
31769
- if (biome) {
31770
- const formatter = biome.formatter;
31771
- if (formatter) {
31772
- const type = formatter.indentStyle === "tab" ? "tab" : "space";
31773
- const width = typeof formatter.indentWidth === "number" ? formatter.indentWidth : 2;
31774
- indentStyle = { type, width };
31775
- }
31776
- }
31777
- if (!indentStyle) {
31778
- const editorConfig = readText(join4(cwd, ".editorconfig"));
31779
- if (editorConfig) {
31780
- const styleMatch = editorConfig.match(/indent_style\s*=\s*(space|tab)/);
31781
- const sizeMatch = editorConfig.match(/indent_size\s*=\s*(\d+)/);
31782
- if (styleMatch) {
31783
- indentStyle = {
31784
- type: styleMatch[1],
31785
- width: sizeMatch ? Number.parseInt(sizeMatch[1], 10) : 2
31786
- };
31787
- }
31788
- }
31789
- }
31790
- const dirs = listDirs(cwd);
31791
- const srcDirs = existsSync4(join4(cwd, "src")) ? listDirs(join4(cwd, "src")) : [];
31792
- const monorepo = existsSync4(join4(cwd, "packages")) || existsSync4(join4(cwd, "apps"));
31793
- const existingDocs = {
31794
- agentsMd: existsSync4(join4(cwd, "AGENTS.md")),
31795
- claudeMd: existsSync4(join4(cwd, "CLAUDE.md")),
31796
- docsDir: existsSync4(join4(cwd, "docs")),
31797
- architectureMd: existsSync4(join4(cwd, "docs", "architecture.md"))
31798
- };
31799
- return {
31800
- packageManager,
31801
- scripts,
31802
- language,
31803
- framework,
31804
- linter,
31805
- indentStyle,
31806
- dirs,
31807
- srcDirs,
31808
- monorepo,
31809
- existingDocs
31810
- };
31811
- }
31812
- function runCmd(pm) {
31813
- if (pm === "bun")
31814
- return "bun run";
31815
- if (pm === "pnpm")
31816
- return "pnpm run";
31817
- if (pm === "yarn")
31818
- return "yarn";
31819
- return "npm run";
31820
- }
31821
- function describeScript(name) {
31822
- const map3 = {
31823
- dev: "Dev server",
31824
- start: "Start server",
31825
- build: "Production build",
31826
- lint: "Lint",
31827
- "lint:fix": "Lint + autofix",
31828
- format: "Format code",
31829
- test: "Run tests",
31830
- "test:watch": "Run tests (watch)",
31831
- "test:e2e": "End-to-end tests",
31832
- typecheck: "Type-check",
31833
- "type-check": "Type-check",
31834
- preview: "Preview production build",
31835
- deploy: "Deploy",
31836
- generate: "Code generation",
31837
- migrate: "Run migrations",
31838
- seed: "Seed database",
31839
- clean: "Clean build artifacts",
31840
- prepare: "Prepare (husky, etc.)"
31841
- };
31842
- return map3[name] ?? "";
31843
- }
31844
- function generateAgentsMd(info, _cwd) {
31845
- const lang = info.language === "typescript" ? "TypeScript" : info.language === "javascript" ? "JavaScript" : info.language;
31846
- const frameworkLabel = info.framework ? `${info.framework} ` : "";
31847
- const monoLabel = info.monorepo ? " (monorepo)" : "";
31848
- const lines = [];
31849
- lines.push("# AGENTS.md");
31850
- lines.push("");
31851
- lines.push(`${frameworkLabel}${lang} project${monoLabel}.`);
31852
- lines.push("");
31853
- const scriptEntries = Object.entries(info.scripts);
31854
- if (scriptEntries.length > 0 && info.packageManager) {
31855
- const prefix = runCmd(info.packageManager);
31856
- lines.push("## Commands");
31857
- lines.push("");
31858
- lines.push("```bash");
31859
- const commands = scriptEntries.map(([name]) => `${prefix} ${name}`);
31860
- const maxLen = Math.max(...commands.map((c) => c.length));
31861
- for (let i = 0;i < scriptEntries.length; i++) {
31862
- const [name] = scriptEntries[i];
31863
- const cmd = commands[i];
31864
- const desc = describeScript(name);
31865
- if (desc) {
31866
- lines.push(`${cmd}${" ".repeat(maxLen - cmd.length + 4)}# ${desc}`);
31867
- } else {
31868
- lines.push(cmd);
31869
- }
31870
- }
31871
- lines.push("```");
31872
- lines.push("");
31873
- }
31874
- lines.push("## Code Standards");
31875
- lines.push("");
31876
- const langLabel = info.language === "typescript" ? "TypeScript" : "JavaScript";
31877
- if (info.language === "typescript" || info.language === "javascript") {
31878
- lines.push(`- ${langLabel} with ES modules`);
31879
- }
31880
- if (info.indentStyle) {
31881
- const unit = info.indentStyle.type === "tab" ? "tab" : "space";
31882
- lines.push(`- ${info.indentStyle.width}-${unit} indentation`);
31883
- }
31884
- if (info.linter) {
31885
- lines.push(`- Linted with ${info.linter}`);
31886
- }
31887
- lines.push("");
31888
- lines.push("## Architecture");
31889
- lines.push("");
31890
- for (const dir of info.dirs) {
31891
- lines.push(`- \`${dir}/\` — ${describeDir(dir)}`);
31892
- }
31893
- if (info.srcDirs.length > 0) {
31894
- for (const sub of info.srcDirs) {
31895
- lines.push(` - \`src/${sub}/\` — ${describeDir(sub)}`);
31896
- }
31897
- }
31898
- lines.push("");
31899
- return lines.join(`
31900
- `);
31901
- }
31902
- function generateClaudeMd(info) {
31903
- const lines = [];
31904
- lines.push("# CLAUDE.md");
31905
- lines.push("");
31906
- lines.push("@AGENTS.md");
31907
- if (info.existingDocs.architectureMd || info.dirs.includes("docs")) {
31908
- lines.push("@docs/architecture.md");
31909
- }
31910
- lines.push("");
31911
- return lines.join(`
31912
- `);
31913
- }
31914
- function generateArchitectureMd(info, _cwd) {
31915
- const lines = [];
31916
- lines.push("# Architecture");
31917
- lines.push("");
31918
- lines.push("## Directory Structure");
31919
- lines.push("");
31920
- for (const dir of info.dirs) {
31921
- lines.push(`- \`${dir}/\` — ${describeDir(dir)}`);
31922
- }
31923
- if (info.srcDirs.length > 0) {
31924
- lines.push("");
31925
- lines.push("### `src/`");
31926
- lines.push("");
31927
- for (const sub of info.srcDirs) {
31928
- lines.push(`- \`src/${sub}/\` — ${describeDir(sub)}`);
31929
- }
31930
- }
31931
- lines.push("");
31932
- return lines.join(`
31933
- `);
31934
- }
31935
- function verifyDocs(cwd) {
31936
- const issues = [];
31937
- const claudeMd = readText(join4(cwd, "CLAUDE.md"));
31938
- if (claudeMd) {
31939
- for (const line of claudeMd.split(`
31940
- `)) {
31941
- const match = line.match(/^@(.+)$/);
31942
- if (match) {
31943
- const refPath = match[1].trim();
31944
- if (!existsSync4(join4(cwd, refPath))) {
31945
- issues.push({
31946
- severity: "error",
31947
- file: "CLAUDE.md",
31948
- message: `Referenced file does not exist: ${refPath}`,
31949
- fix: `Remove the @${refPath} line or create the file`
31950
- });
31951
- }
31952
- }
31953
- }
31954
- }
31955
- const agentsMd = readText(join4(cwd, "AGENTS.md"));
31956
- const pkg = readJson(join4(cwd, "package.json"));
31957
- const pkgScripts = pkg && typeof pkg.scripts === "object" && pkg.scripts !== null ? pkg.scripts : {};
31958
- if (agentsMd) {
31959
- const codeBlockRe = /```[\s\S]*?```/g;
31960
- let blockMatch;
31961
- while ((blockMatch = codeBlockRe.exec(agentsMd)) !== null) {
31962
- const block = blockMatch[0];
31963
- const cmdRe = /(?:bun|npm|pnpm|yarn)\s+(?:run\s+)?(\S+)/g;
31964
- let cmdMatch;
31965
- while ((cmdMatch = cmdRe.exec(block)) !== null) {
31966
- const scriptName = cmdMatch[1];
31967
- const builtins = new Set(["install", "init", "create", "exec", "dlx", "x", "test", "start"]);
31968
- if (builtins.has(scriptName))
31969
- continue;
31970
- if (Object.keys(pkgScripts).length > 0 && !(scriptName in pkgScripts)) {
31971
- issues.push({
31972
- severity: "warning",
31973
- file: "AGENTS.md",
31974
- message: `Command references script "${scriptName}" which is not in package.json`,
31975
- fix: `Update the command or add "${scriptName}" to package.json scripts`
31976
- });
31977
- }
31978
- }
31979
- }
31980
- checkBacktickPaths(agentsMd, "AGENTS.md", cwd, issues);
31981
- }
31982
- const archMd = readText(join4(cwd, "docs", "architecture.md"));
31983
- if (archMd) {
31984
- checkBacktickPaths(archMd, "docs/architecture.md", cwd, issues);
31985
- }
31986
- return issues;
31987
- }
31988
- function checkBacktickPaths(content, file2, cwd, issues) {
31989
- const pathRe = /`((?:src\/|packages\/|apps\/|supabase\/|docs\/)[^`]+)`/g;
31990
- let match;
31991
- const checked = new Set;
31992
- while ((match = pathRe.exec(content)) !== null) {
31993
- const refPath = match[1].replace(/\/$/, "");
31994
- if (checked.has(refPath))
31995
- continue;
31996
- checked.add(refPath);
31997
- if (!existsSync4(join4(cwd, refPath))) {
31998
- issues.push({
31999
- severity: "warning",
32000
- file: file2,
32001
- message: `Referenced path does not exist: ${refPath}`,
32002
- fix: `Update or remove the \`${refPath}\` reference`
32003
- });
32004
- }
32005
- }
32006
- }
32007
- async function runDocsStep(cwd) {
32008
- const info = scanProject(cwd);
32009
- const hasDocs = info.existingDocs.agentsMd || info.existingDocs.claudeMd;
32010
- if (!hasDocs) {
32011
- const shouldGenerate = await ye({
32012
- message: "No project docs found. Generate AGENTS.md and CLAUDE.md?",
32013
- initialValue: true
32014
- });
32015
- if (pD(shouldGenerate) || !shouldGenerate) {
32016
- return { files: [], issues: [], skipped: true };
32017
- }
32018
- const files = [];
32019
- files.push({
32020
- path: join4(cwd, "AGENTS.md"),
32021
- content: generateAgentsMd(info, cwd),
32022
- type: "text"
32023
- });
32024
- files.push({
32025
- path: join4(cwd, "CLAUDE.md"),
32026
- content: generateClaudeMd(info),
32027
- type: "text"
32028
- });
32029
- if (info.dirs.includes("docs") || info.srcDirs.length > 0) {
32030
- files.push({
32031
- path: join4(cwd, "docs", "architecture.md"),
32032
- content: generateArchitectureMd(info, cwd),
32033
- type: "text"
32034
- });
32035
- }
32036
- M2.success(`Generated ${files.length} doc file(s): ${files.map((f) => f.path.replace(cwd + "/", "")).join(", ")}`);
32037
- return { files, issues: [], skipped: false };
32038
- }
32039
- const shouldVerify = await ye({
32040
- message: "Project docs found. Verify for issues?",
32041
- initialValue: false
32042
- });
32043
- if (pD(shouldVerify) || !shouldVerify) {
32044
- return { files: [], issues: [], skipped: true };
32045
- }
32046
- const issues = verifyDocs(cwd);
32047
- if (issues.length === 0) {
32048
- M2.success("No issues found in project docs.");
32049
- } else {
32050
- for (const issue2 of issues) {
32051
- const prefix = `${colors.bold(issue2.file)}:`;
32052
- if (issue2.severity === "error") {
32053
- M2.error(`${prefix} ${issue2.message}`);
32054
- } else {
32055
- M2.warning(`${prefix} ${issue2.message}`);
32056
- }
32057
- if (issue2.fix) {
32058
- M2.message(` ${symbols.arrow} ${colors.dim(issue2.fix)}`);
32059
- }
32060
- }
32061
- M2.info(`Found ${issues.length} issue(s) (${issues.filter((i) => i.severity === "error").length} errors, ${issues.filter((i) => i.severity === "warning").length} warnings)`);
32062
- }
32063
- return { files: [], issues, skipped: false };
32064
- }
32065
-
32066
- // src/tui/writer.ts
32067
- import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "node:fs";
32068
- import { homedir as homedir3 } from "node:os";
32069
- import { dirname } from "node:path";
32070
- function ensureDir(dirPath) {
32071
- if (!existsSync5(dirPath)) {
32072
- mkdirSync3(dirPath, { recursive: true, mode: 493 });
32073
- }
32074
- }
32075
- function writeFile(filePath, content, options = {}) {
32076
- const exists = existsSync5(filePath);
32077
- if (exists && !options.force) {
32078
- return { path: filePath, action: "skip" };
32079
- }
32080
- try {
32081
- ensureDir(dirname(filePath));
32082
- const mode = filePath.includes(".harmony-mcp") ? 384 : 420;
32083
- writeFileSync3(filePath, content, { mode });
32084
- return { path: filePath, action: exists ? "update" : "create" };
32085
- } catch (error48) {
32086
- return {
32087
- path: filePath,
32088
- action: "skip",
32089
- error: error48 instanceof Error ? error48.message : String(error48)
32090
- };
32091
- }
32092
- }
32093
- function mergeJsonFile(filePath, updates, options = {}) {
32094
- const exists = existsSync5(filePath);
32095
- if (!exists) {
32096
- try {
32097
- ensureDir(dirname(filePath));
32098
- writeFileSync3(filePath, JSON.stringify(updates, null, 2), {
32099
- mode: 420
32100
- });
32101
- return { path: filePath, action: "create" };
32102
- } catch (error48) {
32103
- return {
32104
- path: filePath,
32105
- action: "skip",
32106
- error: error48 instanceof Error ? error48.message : String(error48)
32107
- };
32108
- }
32109
- }
32110
- try {
32111
- const existing = JSON.parse(readFileSync4(filePath, "utf-8"));
32112
- if (updates.mcpServers && existing.mcpServers) {
32113
- const existingServers = existing.mcpServers;
32114
- const updateServers = updates.mcpServers;
32115
- existing.mcpServers = { ...existingServers, ...updateServers };
32116
- } else {
32117
- Object.assign(existing, updates);
32118
- }
32119
- writeFileSync3(filePath, JSON.stringify(existing, null, 2), { mode: 420 });
32120
- return { path: filePath, action: "merge" };
32121
- } catch {
32122
- if (options.force) {
32123
- try {
32124
- writeFileSync3(filePath, JSON.stringify(updates, null, 2), {
32125
- mode: 420
32126
- });
32127
- return { path: filePath, action: "update" };
32128
- } catch (error48) {
32129
- return {
32130
- path: filePath,
32131
- action: "skip",
32132
- error: error48 instanceof Error ? error48.message : String(error48)
32133
- };
32134
- }
32135
- }
32136
- return {
32137
- path: filePath,
32138
- action: "skip",
32139
- error: "Could not parse existing file"
32140
- };
32141
- }
32142
- }
32143
- function appendToToml(filePath, section, content, options = {}) {
32144
- const exists = existsSync5(filePath);
32145
- if (!exists) {
32146
- try {
32147
- ensureDir(dirname(filePath));
32148
- writeFileSync3(filePath, content, { mode: 420 });
32149
- return { path: filePath, action: "create" };
32150
- } catch (error48) {
32151
- return {
32152
- path: filePath,
32153
- action: "skip",
32154
- error: error48 instanceof Error ? error48.message : String(error48)
32155
- };
32156
- }
32157
- }
32158
- try {
32159
- const existing = readFileSync4(filePath, "utf-8");
32160
- if (existing.includes(section)) {
32161
- if (options.force) {
32162
- const updated = existing.replace(new RegExp(`\\[${section.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\][\\s\\S]*?(?=\\[|$)`), content.trim() + `
30844
+ User input: $ARGUMENTS
32163
30845
 
32164
- `);
32165
- writeFileSync3(filePath, updated, { mode: 420 });
32166
- return { path: filePath, action: "update" };
32167
- }
32168
- return { path: filePath, action: "skip" };
32169
- }
32170
- writeFileSync3(filePath, existing + `
32171
- ` + content, { mode: 420 });
32172
- return { path: filePath, action: "merge" };
32173
- } catch (error48) {
32174
- return {
32175
- path: filePath,
32176
- action: "skip",
32177
- error: error48 instanceof Error ? error48.message : String(error48)
32178
- };
32179
- }
32180
- }
32181
- async function writeFilesWithProgress(files, options = {}) {
32182
- const results = [];
32183
- const home = homedir3();
32184
- const spinner = Y2();
32185
- spinner.start("Writing configuration files...");
32186
- for (const file2 of files) {
32187
- let result;
32188
- if (file2.type === "json") {
32189
- const jsonContent = JSON.parse(file2.content);
32190
- result = mergeJsonFile(file2.path, jsonContent, options);
32191
- } else if (file2.type === "toml" && file2.tomlSection) {
32192
- result = appendToToml(file2.path, file2.tomlSection, file2.content, options);
32193
- } else {
32194
- result = writeFile(file2.path, file2.content, options);
32195
- }
32196
- results.push(result);
32197
- await new Promise((resolve) => setTimeout(resolve, 50));
32198
- }
32199
- spinner.stop("Files written");
32200
- for (const result of results) {
32201
- const displayPath = formatPath(result.path, home);
32202
- if (result.error) {
32203
- console.log(messages.fileError(displayPath, result.error));
32204
- } else if (result.action === "skip") {
32205
- console.log(messages.fileSkipped(displayPath));
32206
- } else {
32207
- const actionLabel = result.action === "merge" ? "updated" : "created";
32208
- console.log(` ${colors.success("✓")} ${colors.dim(displayPath)} ${colors.dim(`(${actionLabel})`)}`);
32209
- }
32210
- }
32211
- return results;
32212
- }
32213
- function getWriteSummary(files, options = {}) {
32214
- const toCreate = [];
32215
- const toUpdate = [];
32216
- const toSkip = [];
32217
- const home = homedir3();
32218
- for (const file2 of files) {
32219
- const displayPath = formatPath(file2.path, home);
32220
- const exists = existsSync5(file2.path);
32221
- if (exists && !options.force) {
32222
- toSkip.push(displayPath);
32223
- } else if (exists) {
32224
- toUpdate.push(displayPath);
32225
- } else {
32226
- toCreate.push(displayPath);
32227
- }
32228
- }
32229
- return { toCreate, toUpdate, toSkip };
32230
- }
30846
+ ## 0. Detect Intent
32231
30847
 
32232
- // src/tui/setup.ts
32233
- var GLOBAL_SKILLS_DIR = join5(homedir4(), ".agents", "skills");
32234
- var API_URL = "https://gethmy.com/api";
32235
- var HARMONY_WORKFLOW_PROMPT = `# Harmony Card Workflow
30848
+ Parse \`$ARGUMENTS\` to determine what the user wants:
32236
30849
 
32237
- Start work on a Harmony card. Card reference: $ARGUMENTS
30850
+ | Pattern | Intent | Go to |
30851
+ |---|---|---|
30852
+ | \`create ...\` or \`new ...\` | **Create** a new card | Step A |
30853
+ | \`#42\`, \`42\`, UUID, or card name (no action verb) | **Work on** an existing card | Step B |
30854
+ | \`move #42 to Done\`, \`update #42 ...\`, \`assign #42 ...\` | **Quick action** on a card | Step C |
30855
+ | \`show #42\`, \`view #42\`, \`status #42\` | **View** card details | Step D |
32238
30856
 
32239
- ## 1. Find & Fetch Card
30857
+ If ambiguous, ask the user what they'd like to do.
30858
+
30859
+ ---
30860
+
30861
+ ## Step A: Create Card
30862
+
30863
+ Create a card without starting work on it.
30864
+
30865
+ 1. Parse the title and any details from the arguments (e.g., \`create Add dark mode toggle\` → title: "Add dark mode toggle")
30866
+ 2. Call \`harmony_create_card\` with:
30867
+ - \`title\`: extracted title
30868
+ - \`description\`: if the user provided details beyond the title
30869
+ - \`priority\`, \`columnId\`, \`assigneeId\`: only if explicitly specified
30870
+ 3. Show the created card: title, short ID, column, and a link if available.
30871
+ 4. **Stop here.** Do not start an agent session or begin implementation.
30872
+
30873
+ ---
30874
+
30875
+ ## Step B: Work on Existing Card
30876
+
30877
+ Start work on a Harmony card.
30878
+
30879
+ ### B1. Find & Fetch Card
32240
30880
 
32241
30881
  Parse the reference and fetch the card:
32242
30882
  - \`#42\` or \`42\` → \`harmony_get_card_by_short_id\` with \`shortId: 42\`
32243
30883
  - UUID → \`harmony_get_card\` with \`cardId\`
32244
30884
  - Name/text → \`harmony_search_cards\` with \`query\`
32245
30885
 
32246
- ## 2. Get Board State
32247
-
32248
- Call \`harmony_get_board\` to get columns and labels. From the response:
32249
- - Find the "In Progress" (or "Progress") column ID
32250
- - Find the "agent" label ID
30886
+ ### B2. Start Agent Session
32251
30887
 
32252
- ## 3. Setup Card for Work
30888
+ Call \`harmony_start_agent_session\` with:
30889
+ - \`cardId\`: Card UUID
30890
+ - \`agentIdentifier\`: Your agent identifier
30891
+ - \`agentName\`: Your agent name
30892
+ - \`currentTask\`: A specific description of the first thing you'll do (e.g., "Exploring codebase to understand auth flow"), NOT a generic phrase like "Analyzing card requirements"
30893
+ - \`moveToColumn\`: "In Progress"
30894
+ - \`addLabels\`: ["agent"]
32253
30895
 
32254
- Execute these in sequence:
32255
- 1. \`harmony_move_card\` → Move to "In Progress" column
32256
- 2. \`harmony_add_label_to_card\` → Add "agent" label
32257
- 3. \`harmony_start_agent_session\`:
32258
- - \`cardId\`: Card UUID
32259
- - \`agentIdentifier\`: Your agent identifier
32260
- - \`agentName\`: Your agent name
32261
- - \`currentTask\`: "Analyzing card requirements"
30896
+ This single call moves the card, adds the label, auto-assigns, and starts the session.
32262
30897
 
32263
- ## 4. Generate Work Prompt
30898
+ ### B3. Generate Work Prompt
32264
30899
 
32265
30900
  Call \`harmony_generate_prompt\` with:
32266
30901
  - \`cardId\` or \`shortId\` (+ \`projectId\` if using shortId)
@@ -32271,26 +30906,56 @@ Call \`harmony_generate_prompt\` with:
32271
30906
 
32272
30907
  The generated prompt provides role framing, focus areas, subtasks, linked cards, and suggested outputs.
32273
30908
 
32274
- ## 5. Display Card Summary
30909
+ ### B4. Display Card Summary
32275
30910
 
32276
30911
  Show the user: Card title, short ID, role, priority, labels, due date, description, and subtasks.
32277
30912
 
32278
- ## 6. Implement Solution
30913
+ ### B5. Implement Solution
32279
30914
 
32280
- Work on the card following the generated prompt's guidance. Update progress at milestones:
32281
- - \`harmony_update_agent_progress\` with \`progressPercent\` (0-100), \`currentTask\`, \`status\`, \`blockers\`
30915
+ Work on the card following the generated prompt's guidance.
32282
30916
 
32283
- **Progress checkpoints:** 20% (exploration), 50% (implementation), 80% (testing), 100% (done)
30917
+ **REQUIRED: Update progress at each milestone** by calling \`harmony_update_agent_progress\`. This is not optional — the card's live status badge depends on these updates.
32284
30918
 
32285
- ## 7. Complete Work
30919
+ | Milestone | \`progressPercent\` | Example \`currentTask\` |
30920
+ |---|---|---|
30921
+ | After exploring codebase & understanding requirements | 20 | "Reading auth middleware and identifying affected routes" |
30922
+ | When starting implementation | 50 | "Refactoring token validation in auth.ts" |
30923
+ | When moving to testing/verification | 80 | "Running build and verifying changes compile" |
30924
+ | When done, before ending session | 100 | "All changes complete, ready for review" |
30925
+
30926
+ Always set \`currentTask\` to a specific description of what you're actually doing — never leave it as "Analyzing card requirements" or other generic text.
30927
+
30928
+ ### B6. Complete Work
32286
30929
 
32287
30930
  When finished:
32288
- 1. \`harmony_end_agent_session\` with \`status: "completed"\`, \`progressPercent: 100\`
32289
- 2. \`harmony_move_card\` to "Review" column
32290
- 3. Summarize accomplishments
30931
+ 1. \`harmony_end_agent_session\` with \`status: "completed"\`, \`progressPercent: 100\`, \`moveToColumn: "Review"\`
30932
+ 2. Summarize accomplishments
32291
30933
 
32292
30934
  If pausing: \`harmony_end_agent_session\` with \`status: "paused"\`
32293
30935
 
30936
+ ---
30937
+
30938
+ ## Step C: Quick Action
30939
+
30940
+ Fetch the card first (same as B1), then perform the requested action:
30941
+ - **Move:** \`harmony_move_card\` with target column
30942
+ - **Update:** \`harmony_update_card\` with changed fields
30943
+ - **Assign:** \`harmony_assign_card\`
30944
+ - **Label:** \`harmony_add_label_to_card\` / \`harmony_remove_label_from_card\`
30945
+ - **Archive:** \`harmony_archive_card\`
30946
+
30947
+ Show confirmation and stop. Do not start an agent session.
30948
+
30949
+ ---
30950
+
30951
+ ## Step D: View Card
30952
+
30953
+ Fetch the card (same as B1) and display: title, short ID, column, priority, labels, assignee, due date, description, subtasks, and links.
30954
+
30955
+ Do not start an agent session.
30956
+
30957
+ ---
30958
+
32294
30959
  ## Key Tools Reference
32295
30960
 
32296
30961
  **Cards:** \`harmony_get_card\`, \`harmony_get_card_by_short_id\`, \`harmony_search_cards\`, \`harmony_create_card\`, \`harmony_update_card\`, \`harmony_move_card\`, \`harmony_delete_card\`, \`harmony_assign_card\`
@@ -32307,7 +30972,7 @@ If pausing: \`harmony_end_agent_session\` with \`status: "paused"\`
32307
30972
 
32308
30973
  **AI:** \`harmony_generate_prompt\`, \`harmony_process_command\`
32309
30974
  `;
32310
- var HARMONY_PLAN_PROMPT = `# Harmony Plan Workflow
30975
+ var HMY_PLAN_CONTENT = `# Harmony Plan Workflow
32311
30976
 
32312
30977
  Create a new plan or work on an existing one. Argument: $ARGUMENTS
32313
30978
 
@@ -32462,64 +31127,1816 @@ Create a structured markdown document:
32462
31127
  1. **[Task title]** — priority: high
32463
31128
  [Brief description]
32464
31129
 
32465
- 2. **[Task title]** — priority: medium
32466
- [Brief description]
31130
+ 2. **[Task title]** — priority: medium
31131
+ [Brief description]
31132
+
31133
+ [Continue for all tasks...]
31134
+
31135
+ ## Risks & Mitigations
31136
+ | Risk | Mitigation |
31137
+ |------|------------|
31138
+ | ... | ... |
31139
+
31140
+ ## Success Criteria
31141
+ - [ ] [Measurable criterion]
31142
+ \\\`\\\`\\\`
31143
+
31144
+ ### 2B.4 — Create Plan
31145
+
31146
+ Call \`harmony_create_plan\` with:
31147
+ - \`title\`: The plan title
31148
+ - \`content\`: Full markdown document from Step 2B.3
31149
+ - \`source\`: \`"agent"\`
31150
+ - \`workflowPhase\`: \`"plan"\`
31151
+ - \`tasks\`: Array of tasks from the Tasks section, each with:
31152
+ - \`content\`: Task title + brief description
31153
+ - \`priority\`: \`"high"\`, \`"medium"\`, or \`"low"\`
31154
+ - \`status\`: \`"pending"\`
31155
+
31156
+ ### 2B.5 — User Approval
31157
+
31158
+ Show the user:
31159
+ - Plan URL: \`https://gethmy.com/plans/{id}\`
31160
+ - Number of tasks created
31161
+ - Brief summary
31162
+
31163
+ Then ask: **"Ready to execute? I'll create board cards from these tasks and start the execution phase."**
31164
+
31165
+ Options:
31166
+ 1. **Yes, advance to Execute** — proceed to Step 2B.6
31167
+ 2. **Let me review first** — end here, they can advance later from the UI
31168
+ 3. **Make changes** — iterate on the plan
31169
+
31170
+ ### 2B.6 — Advance to Execute
31171
+
31172
+ Call \`harmony_advance_plan\` with:
31173
+ - \`planId\`: The plan ID from Step 2B.4
31174
+ - \`phase\`: \`"execute"\`
31175
+ - \`summary\`: A 2-3 sentence summary of the key decisions made during planning
31176
+
31177
+ Report the result:
31178
+ - "Created N cards in 'To Do'. Use \`/hmy #<id>\` to start working on any card."
31179
+ - List the created cards with their short IDs
31180
+
31181
+ ## Key Tools Reference
31182
+
31183
+ **Discovery:** \`harmony_list_plans\`, \`harmony_get_plan\`, \`harmony_get_card_by_short_id\`
31184
+ **Context:** \`harmony_get_board\`, \`harmony_recall\`, \`harmony_memory_search\`
31185
+ **Planning:** \`harmony_create_plan\`, \`harmony_advance_plan\`, \`harmony_update_plan\`
31186
+ **Execution:** \`harmony_create_card\`, \`harmony_update_card\`
31187
+ `;
31188
+ var SKILL_DEFINITIONS = {
31189
+ hmy: {
31190
+ name: "hmy",
31191
+ description: "Work with Harmony cards — create, view, update, or start working on them. Use when given a card reference like #42, or commands like create, move, update.",
31192
+ argumentHint: "<command or card-reference>",
31193
+ content: HMY_SKILL_CONTENT
31194
+ },
31195
+ "hmy-plan": {
31196
+ name: "hmy-plan",
31197
+ description: "Create a new plan or work on an existing one. Use when asked to plan a feature, execute a plan, review a plan, or given a plan reference.",
31198
+ argumentHint: "[plan name, ID, or topic to plan]",
31199
+ content: HMY_PLAN_CONTENT
31200
+ }
31201
+ };
31202
+ function buildSkillFile(skillId, agentId) {
31203
+ const skill = SKILL_DEFINITIONS[skillId];
31204
+ if (!skill) {
31205
+ throw new Error(`Unknown skill: ${skillId}`);
31206
+ }
31207
+ let content = skill.content;
31208
+ if (agentId === "claude") {
31209
+ content = content.replace("Your agent identifier", "claude-code").replace("Your agent name", "Claude Code");
31210
+ }
31211
+ const frontmatter = `---
31212
+ name: ${skill.name}
31213
+ description: ${skill.description}
31214
+ argument-hint: ${skill.argumentHint}
31215
+ ---`;
31216
+ return `${frontmatter}
31217
+
31218
+ ${content}
31219
+ ${VERSION_MARKER_PREFIX}${SKILLS_VERSION} -->`;
31220
+ }
31221
+ function parseSkillVersion(content) {
31222
+ const match = content.match(/<!-- skills-version:(\d+) -->/);
31223
+ return match ? match[1] : null;
31224
+ }
31225
+ function findSkillFiles(paths) {
31226
+ const results = [];
31227
+ for (const filePath of paths) {
31228
+ if (!existsSync3(filePath))
31229
+ continue;
31230
+ for (const skillId of Object.keys(SKILL_DEFINITIONS)) {
31231
+ if (filePath.includes(`/${skillId}/`) || filePath.includes(`/${skillId}.md`)) {
31232
+ results.push({ skillId, filePath });
31233
+ break;
31234
+ }
31235
+ }
31236
+ }
31237
+ return results;
31238
+ }
31239
+ async function refreshSkills() {
31240
+ try {
31241
+ const status = areSkillsInstalled();
31242
+ if (!status.installed) {
31243
+ return;
31244
+ }
31245
+ const skillFiles = findSkillFiles(status.paths);
31246
+ if (skillFiles.length > 0) {
31247
+ const samplePath = skillFiles[0].filePath;
31248
+ for (const skillId of Object.keys(SKILL_DEFINITIONS)) {
31249
+ const alreadyFound = skillFiles.some((sf) => sf.skillId === skillId);
31250
+ if (alreadyFound)
31251
+ continue;
31252
+ let siblingPath;
31253
+ if (samplePath.endsWith("SKILL.md")) {
31254
+ const parentDir = dirname(dirname(samplePath));
31255
+ siblingPath = `${parentDir}/${skillId}/SKILL.md`;
31256
+ } else {
31257
+ const parentDir = dirname(samplePath);
31258
+ siblingPath = `${parentDir}/${skillId}.md`;
31259
+ }
31260
+ if (existsSync3(siblingPath)) {
31261
+ skillFiles.push({ skillId, filePath: siblingPath });
31262
+ }
31263
+ }
31264
+ }
31265
+ if (skillFiles.length === 0) {
31266
+ return;
31267
+ }
31268
+ let updated = false;
31269
+ for (const { skillId, filePath } of skillFiles) {
31270
+ try {
31271
+ const currentContent = readFileSync3(filePath, "utf-8");
31272
+ const currentVersion = parseSkillVersion(currentContent);
31273
+ if (currentVersion === null || Number(currentVersion) < Number(SKILLS_VERSION)) {
31274
+ const newContent = buildSkillFile(skillId, "claude");
31275
+ const dir = dirname(filePath);
31276
+ if (!existsSync3(dir)) {
31277
+ mkdirSync3(dir, { recursive: true });
31278
+ }
31279
+ writeFileSync3(filePath, newContent);
31280
+ updated = true;
31281
+ }
31282
+ } catch {}
31283
+ }
31284
+ if (updated) {
31285
+ console.error(`Harmony: Updated skills to v${SKILLS_VERSION}`);
31286
+ }
31287
+ } catch {}
31288
+ }
31289
+
31290
+ // src/tui/setup.ts
31291
+ import {
31292
+ existsSync as existsSync7,
31293
+ lstatSync,
31294
+ mkdirSync as mkdirSync5,
31295
+ symlinkSync,
31296
+ unlinkSync
31297
+ } from "node:fs";
31298
+ import { homedir as homedir4 } from "node:os";
31299
+ import { dirname as dirname3, join as join5 } from "node:path";
32467
31300
 
32468
- [Continue for all tasks...]
31301
+ // ../../node_modules/@clack/core/dist/index.mjs
31302
+ var import_sisteransi = __toESM(require_src(), 1);
31303
+ var import_picocolors = __toESM(require_picocolors(), 1);
31304
+ import { stdin as j, stdout as M } from "node:process";
31305
+ import * as g from "node:readline";
31306
+ import O from "node:readline";
31307
+ import { Writable as X } from "node:stream";
31308
+ function DD({ onlyFirst: e = false } = {}) {
31309
+ const t = ["[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?(?:\\u0007|\\u001B\\u005C|\\u009C))", "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))"].join("|");
31310
+ return new RegExp(t, e ? undefined : "g");
31311
+ }
31312
+ var uD = DD();
31313
+ function P(e) {
31314
+ if (typeof e != "string")
31315
+ throw new TypeError(`Expected a \`string\`, got \`${typeof e}\``);
31316
+ return e.replace(uD, "");
31317
+ }
31318
+ function L(e) {
31319
+ return e && e.__esModule && Object.prototype.hasOwnProperty.call(e, "default") ? e.default : e;
31320
+ }
31321
+ var W = { exports: {} };
31322
+ (function(e) {
31323
+ var u = {};
31324
+ e.exports = u, u.eastAsianWidth = function(F) {
31325
+ var s = F.charCodeAt(0), i = F.length == 2 ? F.charCodeAt(1) : 0, D = s;
31326
+ return 55296 <= s && s <= 56319 && 56320 <= i && i <= 57343 && (s &= 1023, i &= 1023, D = s << 10 | i, D += 65536), D == 12288 || 65281 <= D && D <= 65376 || 65504 <= D && D <= 65510 ? "F" : D == 8361 || 65377 <= D && D <= 65470 || 65474 <= D && D <= 65479 || 65482 <= D && D <= 65487 || 65490 <= D && D <= 65495 || 65498 <= D && D <= 65500 || 65512 <= D && D <= 65518 ? "H" : 4352 <= D && D <= 4447 || 4515 <= D && D <= 4519 || 4602 <= D && D <= 4607 || 9001 <= D && D <= 9002 || 11904 <= D && D <= 11929 || 11931 <= D && D <= 12019 || 12032 <= D && D <= 12245 || 12272 <= D && D <= 12283 || 12289 <= D && D <= 12350 || 12353 <= D && D <= 12438 || 12441 <= D && D <= 12543 || 12549 <= D && D <= 12589 || 12593 <= D && D <= 12686 || 12688 <= D && D <= 12730 || 12736 <= D && D <= 12771 || 12784 <= D && D <= 12830 || 12832 <= D && D <= 12871 || 12880 <= D && D <= 13054 || 13056 <= D && D <= 19903 || 19968 <= D && D <= 42124 || 42128 <= D && D <= 42182 || 43360 <= D && D <= 43388 || 44032 <= D && D <= 55203 || 55216 <= D && D <= 55238 || 55243 <= D && D <= 55291 || 63744 <= D && D <= 64255 || 65040 <= D && D <= 65049 || 65072 <= D && D <= 65106 || 65108 <= D && D <= 65126 || 65128 <= D && D <= 65131 || 110592 <= D && D <= 110593 || 127488 <= D && D <= 127490 || 127504 <= D && D <= 127546 || 127552 <= D && D <= 127560 || 127568 <= D && D <= 127569 || 131072 <= D && D <= 194367 || 177984 <= D && D <= 196605 || 196608 <= D && D <= 262141 ? "W" : 32 <= D && D <= 126 || 162 <= D && D <= 163 || 165 <= D && D <= 166 || D == 172 || D == 175 || 10214 <= D && D <= 10221 || 10629 <= D && D <= 10630 ? "Na" : D == 161 || D == 164 || 167 <= D && D <= 168 || D == 170 || 173 <= D && D <= 174 || 176 <= D && D <= 180 || 182 <= D && D <= 186 || 188 <= D && D <= 191 || D == 198 || D == 208 || 215 <= D && D <= 216 || 222 <= D && D <= 225 || D == 230 || 232 <= D && D <= 234 || 236 <= D && D <= 237 || D == 240 || 242 <= D && D <= 243 || 247 <= D && D <= 250 || D == 252 || D == 254 || D == 257 || D == 273 || D == 275 || D == 283 || 294 <= D && D <= 295 || D == 299 || 305 <= D && D <= 307 || D == 312 || 319 <= D && D <= 322 || D == 324 || 328 <= D && D <= 331 || D == 333 || 338 <= D && D <= 339 || 358 <= D && D <= 359 || D == 363 || D == 462 || D == 464 || D == 466 || D == 468 || D == 470 || D == 472 || D == 474 || D == 476 || D == 593 || D == 609 || D == 708 || D == 711 || 713 <= D && D <= 715 || D == 717 || D == 720 || 728 <= D && D <= 731 || D == 733 || D == 735 || 768 <= D && D <= 879 || 913 <= D && D <= 929 || 931 <= D && D <= 937 || 945 <= D && D <= 961 || 963 <= D && D <= 969 || D == 1025 || 1040 <= D && D <= 1103 || D == 1105 || D == 8208 || 8211 <= D && D <= 8214 || 8216 <= D && D <= 8217 || 8220 <= D && D <= 8221 || 8224 <= D && D <= 8226 || 8228 <= D && D <= 8231 || D == 8240 || 8242 <= D && D <= 8243 || D == 8245 || D == 8251 || D == 8254 || D == 8308 || D == 8319 || 8321 <= D && D <= 8324 || D == 8364 || D == 8451 || D == 8453 || D == 8457 || D == 8467 || D == 8470 || 8481 <= D && D <= 8482 || D == 8486 || D == 8491 || 8531 <= D && D <= 8532 || 8539 <= D && D <= 8542 || 8544 <= D && D <= 8555 || 8560 <= D && D <= 8569 || D == 8585 || 8592 <= D && D <= 8601 || 8632 <= D && D <= 8633 || D == 8658 || D == 8660 || D == 8679 || D == 8704 || 8706 <= D && D <= 8707 || 8711 <= D && D <= 8712 || D == 8715 || D == 8719 || D == 8721 || D == 8725 || D == 8730 || 8733 <= D && D <= 8736 || D == 8739 || D == 8741 || 8743 <= D && D <= 8748 || D == 8750 || 8756 <= D && D <= 8759 || 8764 <= D && D <= 8765 || D == 8776 || D == 8780 || D == 8786 || 8800 <= D && D <= 8801 || 8804 <= D && D <= 8807 || 8810 <= D && D <= 8811 || 8814 <= D && D <= 8815 || 8834 <= D && D <= 8835 || 8838 <= D && D <= 8839 || D == 8853 || D == 8857 || D == 8869 || D == 8895 || D == 8978 || 9312 <= D && D <= 9449 || 9451 <= D && D <= 9547 || 9552 <= D && D <= 9587 || 9600 <= D && D <= 9615 || 9618 <= D && D <= 9621 || 9632 <= D && D <= 9633 || 9635 <= D && D <= 9641 || 9650 <= D && D <= 9651 || 9654 <= D && D <= 9655 || 9660 <= D && D <= 9661 || 9664 <= D && D <= 9665 || 9670 <= D && D <= 9672 || D == 9675 || 9678 <= D && D <= 9681 || 9698 <= D && D <= 9701 || D == 9711 || 9733 <= D && D <= 9734 || D == 9737 || 9742 <= D && D <= 9743 || 9748 <= D && D <= 9749 || D == 9756 || D == 9758 || D == 9792 || D == 9794 || 9824 <= D && D <= 9825 || 9827 <= D && D <= 9829 || 9831 <= D && D <= 9834 || 9836 <= D && D <= 9837 || D == 9839 || 9886 <= D && D <= 9887 || 9918 <= D && D <= 9919 || 9924 <= D && D <= 9933 || 9935 <= D && D <= 9953 || D == 9955 || 9960 <= D && D <= 9983 || D == 10045 || D == 10071 || 10102 <= D && D <= 10111 || 11093 <= D && D <= 11097 || 12872 <= D && D <= 12879 || 57344 <= D && D <= 63743 || 65024 <= D && D <= 65039 || D == 65533 || 127232 <= D && D <= 127242 || 127248 <= D && D <= 127277 || 127280 <= D && D <= 127337 || 127344 <= D && D <= 127386 || 917760 <= D && D <= 917999 || 983040 <= D && D <= 1048573 || 1048576 <= D && D <= 1114109 ? "A" : "N";
31327
+ }, u.characterLength = function(F) {
31328
+ var s = this.eastAsianWidth(F);
31329
+ return s == "F" || s == "W" || s == "A" ? 2 : 1;
31330
+ };
31331
+ function t(F) {
31332
+ return F.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[^\uD800-\uDFFF]/g) || [];
31333
+ }
31334
+ u.length = function(F) {
31335
+ for (var s = t(F), i = 0, D = 0;D < s.length; D++)
31336
+ i = i + this.characterLength(s[D]);
31337
+ return i;
31338
+ }, u.slice = function(F, s, i) {
31339
+ textLen = u.length(F), s = s || 0, i = i || 1, s < 0 && (s = textLen + s), i < 0 && (i = textLen + i);
31340
+ for (var D = "", C = 0, n = t(F), E = 0;E < n.length; E++) {
31341
+ var a = n[E], o = u.length(a);
31342
+ if (C >= s - (o == 2 ? 1 : 0))
31343
+ if (C + o <= i)
31344
+ D += a;
31345
+ else
31346
+ break;
31347
+ C += o;
31348
+ }
31349
+ return D;
31350
+ };
31351
+ })(W);
31352
+ var tD = W.exports;
31353
+ var eD = L(tD);
31354
+ var FD = function() {
31355
+ return /\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62(?:\uDB40\uDC77\uDB40\uDC6C\uDB40\uDC73|\uDB40\uDC73\uDB40\uDC63\uDB40\uDC74|\uDB40\uDC65\uDB40\uDC6E\uDB40\uDC67)\uDB40\uDC7F|(?:\uD83E\uDDD1\uD83C\uDFFF\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB-\uDFFE])|(?:\uD83E\uDDD1\uD83C\uDFFE\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFD\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFC\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFB\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFB\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFC-\uDFFF])|\uD83D\uDC68(?:\uD83C\uDFFB(?:\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF]))|\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFC-\uDFFF])|[\u2695\u2696\u2708]\uFE0F|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))?|(?:\uD83C[\uDFFC-\uDFFF])\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFF]))|\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83D\uDC68|(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFE])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])\uFE0F|\u200D(?:(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D[\uDC66\uDC67])|\uD83D[\uDC66\uDC67])|\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC)?|(?:\uD83D\uDC69(?:\uD83C\uDFFB\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|(?:\uD83C[\uDFFC-\uDFFF])\u200D\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69]))|\uD83E\uDDD1(?:\uD83C[\uDFFB-\uDFFF])\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1)(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC69(?:\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83E\uDDD1(?:\u200D(?:\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83D\uDC69\u200D\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D[\uDC66\uDC67])|\uD83D\uDC69\u200D\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|(?:\uD83D\uDC41\uFE0F\u200D\uD83D\uDDE8|\uD83E\uDDD1(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|\uD83D\uDC69(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|\uD83D\uDE36\u200D\uD83C\uDF2B|\uD83C\uDFF3\uFE0F\u200D\u26A7|\uD83D\uDC3B\u200D\u2744|(?:(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|\uD83D\uDC6F|\uD83E[\uDD3C\uDDDE\uDDDF])\u200D[\u2640\u2642]|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])\u200D[\u2640\u2642]|\uD83C\uDFF4\u200D\u2620|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])\u200D[\u2640\u2642]|[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u2328\u23CF\u23ED-\u23EF\u23F1\u23F2\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB\u25FC\u2600-\u2604\u260E\u2611\u2618\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u2692\u2694-\u2697\u2699\u269B\u269C\u26A0\u26A7\u26B0\u26B1\u26C8\u26CF\u26D1\u26D3\u26E9\u26F0\u26F1\u26F4\u26F7\u26F8\u2702\u2708\u2709\u270F\u2712\u2714\u2716\u271D\u2721\u2733\u2734\u2744\u2747\u2763\u27A1\u2934\u2935\u2B05-\u2B07\u3030\u303D\u3297\u3299]|\uD83C[\uDD70\uDD71\uDD7E\uDD7F\uDE02\uDE37\uDF21\uDF24-\uDF2C\uDF36\uDF7D\uDF96\uDF97\uDF99-\uDF9B\uDF9E\uDF9F\uDFCD\uDFCE\uDFD4-\uDFDF\uDFF5\uDFF7]|\uD83D[\uDC3F\uDCFD\uDD49\uDD4A\uDD6F\uDD70\uDD73\uDD76-\uDD79\uDD87\uDD8A-\uDD8D\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA\uDECB\uDECD-\uDECF\uDEE0-\uDEE5\uDEE9\uDEF0\uDEF3])\uFE0F|\uD83C\uDFF3\uFE0F\u200D\uD83C\uDF08|\uD83D\uDC69\u200D\uD83D\uDC67|\uD83D\uDC69\u200D\uD83D\uDC66|\uD83D\uDE35\u200D\uD83D\uDCAB|\uD83D\uDE2E\u200D\uD83D\uDCA8|\uD83D\uDC15\u200D\uD83E\uDDBA|\uD83E\uDDD1(?:\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC|\uD83C\uDFFB)?|\uD83D\uDC69(?:\uD83C\uDFFF|\uD83C\uDFFE|\uD83C\uDFFD|\uD83C\uDFFC|\uD83C\uDFFB)?|\uD83C\uDDFD\uD83C\uDDF0|\uD83C\uDDF6\uD83C\uDDE6|\uD83C\uDDF4\uD83C\uDDF2|\uD83D\uDC08\u200D\u2B1B|\u2764\uFE0F\u200D(?:\uD83D\uDD25|\uD83E\uDE79)|\uD83D\uDC41\uFE0F|\uD83C\uDFF3\uFE0F|\uD83C\uDDFF(?:\uD83C[\uDDE6\uDDF2\uDDFC])|\uD83C\uDDFE(?:\uD83C[\uDDEA\uDDF9])|\uD83C\uDDFC(?:\uD83C[\uDDEB\uDDF8])|\uD83C\uDDFB(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA])|\uD83C\uDDFA(?:\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF])|\uD83C\uDDF9(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF])|\uD83C\uDDF8(?:\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF])|\uD83C\uDDF7(?:\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC])|\uD83C\uDDF5(?:\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE])|\uD83C\uDDF3(?:\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF])|\uD83C\uDDF2(?:\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF])|\uD83C\uDDF1(?:\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE])|\uD83C\uDDF0(?:\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF])|\uD83C\uDDEF(?:\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5])|\uD83C\uDDEE(?:\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9])|\uD83C\uDDED(?:\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA])|\uD83C\uDDEC(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE])|\uD83C\uDDEB(?:\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7])|\uD83C\uDDEA(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA])|\uD83C\uDDE9(?:\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF])|\uD83C\uDDE8(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF])|\uD83C\uDDE7(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF])|\uD83C\uDDE6(?:\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF])|[#\*0-9]\uFE0F\u20E3|\u2764\uFE0F|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])|\uD83C\uDFF4|(?:[\u270A\u270B]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5])(?:\uD83C[\uDFFB-\uDFFF])|(?:[\u261D\u270C\u270D]|\uD83D[\uDD74\uDD90])(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])|[\u270A\u270B]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC08\uDC15\uDC3B\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE2E\uDE35\uDE36\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5]|\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD]|\uD83D\uDC6F|\uD83E[\uDD3C\uDDDE\uDDDF]|[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF84\uDF86-\uDF93\uDFA0-\uDFC1\uDFC5\uDFC6\uDFC8\uDFC9\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC07\uDC09-\uDC14\uDC16-\uDC3A\uDC3C-\uDC3E\uDC40\uDC44\uDC45\uDC51-\uDC65\uDC6A\uDC79-\uDC7B\uDC7D-\uDC80\uDC84\uDC88-\uDC8E\uDC90\uDC92-\uDCA9\uDCAB-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDDA4\uDDFB-\uDE2D\uDE2F-\uDE34\uDE37-\uDE44\uDE48-\uDE4A\uDE80-\uDEA2\uDEA4-\uDEB3\uDEB7-\uDEBF\uDEC1-\uDEC5\uDED0-\uDED2\uDED5-\uDED7\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0D\uDD0E\uDD10-\uDD17\uDD1D\uDD20-\uDD25\uDD27-\uDD2F\uDD3A\uDD3F-\uDD45\uDD47-\uDD76\uDD78\uDD7A-\uDDB4\uDDB7\uDDBA\uDDBC-\uDDCB\uDDD0\uDDE0-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6]|(?:[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u270A\u270B\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF93\uDFA0-\uDFCA\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF4\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC3E\uDC40\uDC42-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDD7A\uDD95\uDD96\uDDA4\uDDFB-\uDE4F\uDE80-\uDEC5\uDECC\uDED0-\uDED2\uDED5-\uDED7\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0C-\uDD3A\uDD3C-\uDD45\uDD47-\uDD78\uDD7A-\uDDCB\uDDCD-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6])|(?:[#\*0-9\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692-\u2697\u2699\u269B\u269C\u26A0\u26A1\u26A7\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD7A\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA4\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED2\uDED5-\uDED7\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0C-\uDD3A\uDD3C-\uDD45\uDD47-\uDD78\uDD7A-\uDDCB\uDDCD-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6])\uFE0F|(?:[\u261D\u26F9\u270A-\u270D]|\uD83C[\uDF85\uDFC2-\uDFC4\uDFC7\uDFCA-\uDFCC]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66-\uDC78\uDC7C\uDC81-\uDC83\uDC85-\uDC87\uDC8F\uDC91\uDCAA\uDD74\uDD75\uDD7A\uDD90\uDD95\uDD96\uDE45-\uDE47\uDE4B-\uDE4F\uDEA3\uDEB4-\uDEB6\uDEC0\uDECC]|\uD83E[\uDD0C\uDD0F\uDD18-\uDD1F\uDD26\uDD30-\uDD39\uDD3C-\uDD3E\uDD77\uDDB5\uDDB6\uDDB8\uDDB9\uDDBB\uDDCD-\uDDCF\uDDD1-\uDDDD])/g;
31356
+ };
31357
+ var sD = L(FD);
31358
+ function p(e, u = {}) {
31359
+ if (typeof e != "string" || e.length === 0 || (u = { ambiguousIsNarrow: true, ...u }, e = P(e), e.length === 0))
31360
+ return 0;
31361
+ e = e.replace(sD(), " ");
31362
+ const t = u.ambiguousIsNarrow ? 1 : 2;
31363
+ let F = 0;
31364
+ for (const s of e) {
31365
+ const i = s.codePointAt(0);
31366
+ if (i <= 31 || i >= 127 && i <= 159 || i >= 768 && i <= 879)
31367
+ continue;
31368
+ switch (eD.eastAsianWidth(s)) {
31369
+ case "F":
31370
+ case "W":
31371
+ F += 2;
31372
+ break;
31373
+ case "A":
31374
+ F += t;
31375
+ break;
31376
+ default:
31377
+ F += 1;
31378
+ }
31379
+ }
31380
+ return F;
31381
+ }
31382
+ var w = 10;
31383
+ var N = (e = 0) => (u) => `\x1B[${u + e}m`;
31384
+ var I = (e = 0) => (u) => `\x1B[${38 + e};5;${u}m`;
31385
+ var R = (e = 0) => (u, t, F) => `\x1B[${38 + e};2;${u};${t};${F}m`;
31386
+ var r = { modifier: { reset: [0, 0], bold: [1, 22], dim: [2, 22], italic: [3, 23], underline: [4, 24], overline: [53, 55], inverse: [7, 27], hidden: [8, 28], strikethrough: [9, 29] }, color: { black: [30, 39], red: [31, 39], green: [32, 39], yellow: [33, 39], blue: [34, 39], magenta: [35, 39], cyan: [36, 39], white: [37, 39], blackBright: [90, 39], gray: [90, 39], grey: [90, 39], redBright: [91, 39], greenBright: [92, 39], yellowBright: [93, 39], blueBright: [94, 39], magentaBright: [95, 39], cyanBright: [96, 39], whiteBright: [97, 39] }, bgColor: { bgBlack: [40, 49], bgRed: [41, 49], bgGreen: [42, 49], bgYellow: [43, 49], bgBlue: [44, 49], bgMagenta: [45, 49], bgCyan: [46, 49], bgWhite: [47, 49], bgBlackBright: [100, 49], bgGray: [100, 49], bgGrey: [100, 49], bgRedBright: [101, 49], bgGreenBright: [102, 49], bgYellowBright: [103, 49], bgBlueBright: [104, 49], bgMagentaBright: [105, 49], bgCyanBright: [106, 49], bgWhiteBright: [107, 49] } };
31387
+ Object.keys(r.modifier);
31388
+ var iD = Object.keys(r.color);
31389
+ var CD = Object.keys(r.bgColor);
31390
+ [...iD, ...CD];
31391
+ function rD() {
31392
+ const e = new Map;
31393
+ for (const [u, t] of Object.entries(r)) {
31394
+ for (const [F, s] of Object.entries(t))
31395
+ r[F] = { open: `\x1B[${s[0]}m`, close: `\x1B[${s[1]}m` }, t[F] = r[F], e.set(s[0], s[1]);
31396
+ Object.defineProperty(r, u, { value: t, enumerable: false });
31397
+ }
31398
+ return Object.defineProperty(r, "codes", { value: e, enumerable: false }), r.color.close = "\x1B[39m", r.bgColor.close = "\x1B[49m", r.color.ansi = N(), r.color.ansi256 = I(), r.color.ansi16m = R(), r.bgColor.ansi = N(w), r.bgColor.ansi256 = I(w), r.bgColor.ansi16m = R(w), Object.defineProperties(r, { rgbToAnsi256: { value: (u, t, F) => u === t && t === F ? u < 8 ? 16 : u > 248 ? 231 : Math.round((u - 8) / 247 * 24) + 232 : 16 + 36 * Math.round(u / 255 * 5) + 6 * Math.round(t / 255 * 5) + Math.round(F / 255 * 5), enumerable: false }, hexToRgb: { value: (u) => {
31399
+ const t = /[a-f\d]{6}|[a-f\d]{3}/i.exec(u.toString(16));
31400
+ if (!t)
31401
+ return [0, 0, 0];
31402
+ let [F] = t;
31403
+ F.length === 3 && (F = [...F].map((i) => i + i).join(""));
31404
+ const s = Number.parseInt(F, 16);
31405
+ return [s >> 16 & 255, s >> 8 & 255, s & 255];
31406
+ }, enumerable: false }, hexToAnsi256: { value: (u) => r.rgbToAnsi256(...r.hexToRgb(u)), enumerable: false }, ansi256ToAnsi: { value: (u) => {
31407
+ if (u < 8)
31408
+ return 30 + u;
31409
+ if (u < 16)
31410
+ return 90 + (u - 8);
31411
+ let t, F, s;
31412
+ if (u >= 232)
31413
+ t = ((u - 232) * 10 + 8) / 255, F = t, s = t;
31414
+ else {
31415
+ u -= 16;
31416
+ const C = u % 36;
31417
+ t = Math.floor(u / 36) / 5, F = Math.floor(C / 6) / 5, s = C % 6 / 5;
31418
+ }
31419
+ const i = Math.max(t, F, s) * 2;
31420
+ if (i === 0)
31421
+ return 30;
31422
+ let D = 30 + (Math.round(s) << 2 | Math.round(F) << 1 | Math.round(t));
31423
+ return i === 2 && (D += 60), D;
31424
+ }, enumerable: false }, rgbToAnsi: { value: (u, t, F) => r.ansi256ToAnsi(r.rgbToAnsi256(u, t, F)), enumerable: false }, hexToAnsi: { value: (u) => r.ansi256ToAnsi(r.hexToAnsi256(u)), enumerable: false } }), r;
31425
+ }
31426
+ var ED = rD();
31427
+ var d = new Set(["\x1B", "›"]);
31428
+ var oD = 39;
31429
+ var y = "\x07";
31430
+ var V = "[";
31431
+ var nD = "]";
31432
+ var G = "m";
31433
+ var _ = `${nD}8;;`;
31434
+ var z2 = (e) => `${d.values().next().value}${V}${e}${G}`;
31435
+ var K = (e) => `${d.values().next().value}${_}${e}${y}`;
31436
+ var aD = (e) => e.split(" ").map((u) => p(u));
31437
+ var k = (e, u, t) => {
31438
+ const F = [...u];
31439
+ let s = false, i = false, D = p(P(e[e.length - 1]));
31440
+ for (const [C, n] of F.entries()) {
31441
+ const E = p(n);
31442
+ if (D + E <= t ? e[e.length - 1] += n : (e.push(n), D = 0), d.has(n) && (s = true, i = F.slice(C + 1).join("").startsWith(_)), s) {
31443
+ i ? n === y && (s = false, i = false) : n === G && (s = false);
31444
+ continue;
31445
+ }
31446
+ D += E, D === t && C < F.length - 1 && (e.push(""), D = 0);
31447
+ }
31448
+ !D && e[e.length - 1].length > 0 && e.length > 1 && (e[e.length - 2] += e.pop());
31449
+ };
31450
+ var hD = (e) => {
31451
+ const u = e.split(" ");
31452
+ let t = u.length;
31453
+ for (;t > 0 && !(p(u[t - 1]) > 0); )
31454
+ t--;
31455
+ return t === u.length ? e : u.slice(0, t).join(" ") + u.slice(t).join("");
31456
+ };
31457
+ var lD = (e, u, t = {}) => {
31458
+ if (t.trim !== false && e.trim() === "")
31459
+ return "";
31460
+ let F = "", s, i;
31461
+ const D = aD(e);
31462
+ let C = [""];
31463
+ for (const [E, a] of e.split(" ").entries()) {
31464
+ t.trim !== false && (C[C.length - 1] = C[C.length - 1].trimStart());
31465
+ let o = p(C[C.length - 1]);
31466
+ if (E !== 0 && (o >= u && (t.wordWrap === false || t.trim === false) && (C.push(""), o = 0), (o > 0 || t.trim === false) && (C[C.length - 1] += " ", o++)), t.hard && D[E] > u) {
31467
+ const c = u - o, f = 1 + Math.floor((D[E] - c - 1) / u);
31468
+ Math.floor((D[E] - 1) / u) < f && C.push(""), k(C, a, u);
31469
+ continue;
31470
+ }
31471
+ if (o + D[E] > u && o > 0 && D[E] > 0) {
31472
+ if (t.wordWrap === false && o < u) {
31473
+ k(C, a, u);
31474
+ continue;
31475
+ }
31476
+ C.push("");
31477
+ }
31478
+ if (o + D[E] > u && t.wordWrap === false) {
31479
+ k(C, a, u);
31480
+ continue;
31481
+ }
31482
+ C[C.length - 1] += a;
31483
+ }
31484
+ t.trim !== false && (C = C.map((E) => hD(E)));
31485
+ const n = [...C.join(`
31486
+ `)];
31487
+ for (const [E, a] of n.entries()) {
31488
+ if (F += a, d.has(a)) {
31489
+ const { groups: c } = new RegExp(`(?:\\${V}(?<code>\\d+)m|\\${_}(?<uri>.*)${y})`).exec(n.slice(E).join("")) || { groups: {} };
31490
+ if (c.code !== undefined) {
31491
+ const f = Number.parseFloat(c.code);
31492
+ s = f === oD ? undefined : f;
31493
+ } else
31494
+ c.uri !== undefined && (i = c.uri.length === 0 ? undefined : c.uri);
31495
+ }
31496
+ const o = ED.codes.get(Number(s));
31497
+ n[E + 1] === `
31498
+ ` ? (i && (F += K("")), s && o && (F += z2(o))) : a === `
31499
+ ` && (s && o && (F += z2(s)), i && (F += K(i)));
31500
+ }
31501
+ return F;
31502
+ };
31503
+ function Y(e, u, t) {
31504
+ return String(e).normalize().replace(/\r\n/g, `
31505
+ `).split(`
31506
+ `).map((F) => lD(F, u, t)).join(`
31507
+ `);
31508
+ }
31509
+ var xD = ["up", "down", "left", "right", "space", "enter", "cancel"];
31510
+ var B = { actions: new Set(xD), aliases: new Map([["k", "up"], ["j", "down"], ["h", "left"], ["l", "right"], ["\x03", "cancel"], ["escape", "cancel"]]) };
31511
+ function $(e, u) {
31512
+ if (typeof e == "string")
31513
+ return B.aliases.get(e) === u;
31514
+ for (const t of e)
31515
+ if (t !== undefined && $(t, u))
31516
+ return true;
31517
+ return false;
31518
+ }
31519
+ function BD(e, u) {
31520
+ if (e === u)
31521
+ return;
31522
+ const t = e.split(`
31523
+ `), F = u.split(`
31524
+ `), s = [];
31525
+ for (let i = 0;i < Math.max(t.length, F.length); i++)
31526
+ t[i] !== F[i] && s.push(i);
31527
+ return s;
31528
+ }
31529
+ var AD = globalThis.process.platform.startsWith("win");
31530
+ var S = Symbol("clack:cancel");
31531
+ function pD(e) {
31532
+ return e === S;
31533
+ }
31534
+ function m(e, u) {
31535
+ const t = e;
31536
+ t.isTTY && t.setRawMode(u);
31537
+ }
31538
+ function fD({ input: e = j, output: u = M, overwrite: t = true, hideCursor: F = true } = {}) {
31539
+ const s = g.createInterface({ input: e, output: u, prompt: "", tabSize: 1 });
31540
+ g.emitKeypressEvents(e, s), e.isTTY && e.setRawMode(true);
31541
+ const i = (D, { name: C, sequence: n }) => {
31542
+ const E = String(D);
31543
+ if ($([E, C, n], "cancel")) {
31544
+ F && u.write(import_sisteransi.cursor.show), process.exit(0);
31545
+ return;
31546
+ }
31547
+ if (!t)
31548
+ return;
31549
+ const a = C === "return" ? 0 : -1, o = C === "return" ? -1 : 0;
31550
+ g.moveCursor(u, a, o, () => {
31551
+ g.clearLine(u, 1, () => {
31552
+ e.once("keypress", i);
31553
+ });
31554
+ });
31555
+ };
31556
+ return F && u.write(import_sisteransi.cursor.hide), e.once("keypress", i), () => {
31557
+ e.off("keypress", i), F && u.write(import_sisteransi.cursor.show), e.isTTY && !AD && e.setRawMode(false), s.terminal = false, s.close();
31558
+ };
31559
+ }
31560
+ var gD = Object.defineProperty;
31561
+ var vD = (e, u, t) => (u in e) ? gD(e, u, { enumerable: true, configurable: true, writable: true, value: t }) : e[u] = t;
31562
+ var h = (e, u, t) => (vD(e, typeof u != "symbol" ? u + "" : u, t), t);
32469
31563
 
32470
- ## Risks & Mitigations
32471
- | Risk | Mitigation |
32472
- |------|------------|
32473
- | ... | ... |
31564
+ class x {
31565
+ constructor(u, t = true) {
31566
+ h(this, "input"), h(this, "output"), h(this, "_abortSignal"), h(this, "rl"), h(this, "opts"), h(this, "_render"), h(this, "_track", false), h(this, "_prevFrame", ""), h(this, "_subscribers", new Map), h(this, "_cursor", 0), h(this, "state", "initial"), h(this, "error", ""), h(this, "value");
31567
+ const { input: F = j, output: s = M, render: i, signal: D, ...C } = u;
31568
+ this.opts = C, this.onKeypress = this.onKeypress.bind(this), this.close = this.close.bind(this), this.render = this.render.bind(this), this._render = i.bind(this), this._track = t, this._abortSignal = D, this.input = F, this.output = s;
31569
+ }
31570
+ unsubscribe() {
31571
+ this._subscribers.clear();
31572
+ }
31573
+ setSubscriber(u, t) {
31574
+ const F = this._subscribers.get(u) ?? [];
31575
+ F.push(t), this._subscribers.set(u, F);
31576
+ }
31577
+ on(u, t) {
31578
+ this.setSubscriber(u, { cb: t });
31579
+ }
31580
+ once(u, t) {
31581
+ this.setSubscriber(u, { cb: t, once: true });
31582
+ }
31583
+ emit(u, ...t) {
31584
+ const F = this._subscribers.get(u) ?? [], s = [];
31585
+ for (const i of F)
31586
+ i.cb(...t), i.once && s.push(() => F.splice(F.indexOf(i), 1));
31587
+ for (const i of s)
31588
+ i();
31589
+ }
31590
+ prompt() {
31591
+ return new Promise((u, t) => {
31592
+ if (this._abortSignal) {
31593
+ if (this._abortSignal.aborted)
31594
+ return this.state = "cancel", this.close(), u(S);
31595
+ this._abortSignal.addEventListener("abort", () => {
31596
+ this.state = "cancel", this.close();
31597
+ }, { once: true });
31598
+ }
31599
+ const F = new X;
31600
+ F._write = (s, i, D) => {
31601
+ this._track && (this.value = this.rl?.line.replace(/\t/g, ""), this._cursor = this.rl?.cursor ?? 0, this.emit("value", this.value)), D();
31602
+ }, this.input.pipe(F), this.rl = O.createInterface({ input: this.input, output: F, tabSize: 2, prompt: "", escapeCodeTimeout: 50, terminal: true }), O.emitKeypressEvents(this.input, this.rl), this.rl.prompt(), this.opts.initialValue !== undefined && this._track && this.rl.write(this.opts.initialValue), this.input.on("keypress", this.onKeypress), m(this.input, true), this.output.on("resize", this.render), this.render(), this.once("submit", () => {
31603
+ this.output.write(import_sisteransi.cursor.show), this.output.off("resize", this.render), m(this.input, false), u(this.value);
31604
+ }), this.once("cancel", () => {
31605
+ this.output.write(import_sisteransi.cursor.show), this.output.off("resize", this.render), m(this.input, false), u(S);
31606
+ });
31607
+ });
31608
+ }
31609
+ onKeypress(u, t) {
31610
+ if (this.state === "error" && (this.state = "active"), t?.name && (!this._track && B.aliases.has(t.name) && this.emit("cursor", B.aliases.get(t.name)), B.actions.has(t.name) && this.emit("cursor", t.name)), u && (u.toLowerCase() === "y" || u.toLowerCase() === "n") && this.emit("confirm", u.toLowerCase() === "y"), u === "\t" && this.opts.placeholder && (this.value || (this.rl?.write(this.opts.placeholder), this.emit("value", this.opts.placeholder))), u && this.emit("key", u.toLowerCase()), t?.name === "return") {
31611
+ if (this.opts.validate) {
31612
+ const F = this.opts.validate(this.value);
31613
+ F && (this.error = F instanceof Error ? F.message : F, this.state = "error", this.rl?.write(this.value));
31614
+ }
31615
+ this.state !== "error" && (this.state = "submit");
31616
+ }
31617
+ $([u, t?.name, t?.sequence], "cancel") && (this.state = "cancel"), (this.state === "submit" || this.state === "cancel") && this.emit("finalize"), this.render(), (this.state === "submit" || this.state === "cancel") && this.close();
31618
+ }
31619
+ close() {
31620
+ this.input.unpipe(), this.input.removeListener("keypress", this.onKeypress), this.output.write(`
31621
+ `), m(this.input, false), this.rl?.close(), this.rl = undefined, this.emit(`${this.state}`, this.value), this.unsubscribe();
31622
+ }
31623
+ restoreCursor() {
31624
+ const u = Y(this._prevFrame, process.stdout.columns, { hard: true }).split(`
31625
+ `).length - 1;
31626
+ this.output.write(import_sisteransi.cursor.move(-999, u * -1));
31627
+ }
31628
+ render() {
31629
+ const u = Y(this._render(this) ?? "", process.stdout.columns, { hard: true });
31630
+ if (u !== this._prevFrame) {
31631
+ if (this.state === "initial")
31632
+ this.output.write(import_sisteransi.cursor.hide);
31633
+ else {
31634
+ const t = BD(this._prevFrame, u);
31635
+ if (this.restoreCursor(), t && t?.length === 1) {
31636
+ const F = t[0];
31637
+ this.output.write(import_sisteransi.cursor.move(0, F)), this.output.write(import_sisteransi.erase.lines(1));
31638
+ const s = u.split(`
31639
+ `);
31640
+ this.output.write(s[F]), this._prevFrame = u, this.output.write(import_sisteransi.cursor.move(0, s.length - F - 1));
31641
+ return;
31642
+ }
31643
+ if (t && t?.length > 1) {
31644
+ const F = t[0];
31645
+ this.output.write(import_sisteransi.cursor.move(0, F)), this.output.write(import_sisteransi.erase.down());
31646
+ const s = u.split(`
31647
+ `).slice(F);
31648
+ this.output.write(s.join(`
31649
+ `)), this._prevFrame = u;
31650
+ return;
31651
+ }
31652
+ this.output.write(import_sisteransi.erase.down());
31653
+ }
31654
+ this.output.write(u), this.state === "initial" && (this.state = "active"), this._prevFrame = u;
31655
+ }
31656
+ }
31657
+ }
32474
31658
 
32475
- ## Success Criteria
32476
- - [ ] [Measurable criterion]
32477
- \\\`\\\`\\\`
31659
+ class dD extends x {
31660
+ get cursor() {
31661
+ return this.value ? 0 : 1;
31662
+ }
31663
+ get _value() {
31664
+ return this.cursor === 0;
31665
+ }
31666
+ constructor(u) {
31667
+ super(u, false), this.value = !!u.initialValue, this.on("value", () => {
31668
+ this.value = this._value;
31669
+ }), this.on("confirm", (t) => {
31670
+ this.output.write(import_sisteransi.cursor.move(0, -1)), this.value = t, this.state = "submit", this.close();
31671
+ }), this.on("cursor", () => {
31672
+ this.value = !this.value;
31673
+ });
31674
+ }
31675
+ }
31676
+ var A;
31677
+ A = new WeakMap;
31678
+ var kD = Object.defineProperty;
31679
+ var $D = (e, u, t) => (u in e) ? kD(e, u, { enumerable: true, configurable: true, writable: true, value: t }) : e[u] = t;
31680
+ var H = (e, u, t) => ($D(e, typeof u != "symbol" ? u + "" : u, t), t);
31681
+ var SD = class extends x {
31682
+ constructor(u) {
31683
+ super(u, false), H(this, "options"), H(this, "cursor", 0), this.options = u.options, this.value = [...u.initialValues ?? []], this.cursor = Math.max(this.options.findIndex(({ value: t }) => t === u.cursorAt), 0), this.on("key", (t) => {
31684
+ t === "a" && this.toggleAll();
31685
+ }), this.on("cursor", (t) => {
31686
+ switch (t) {
31687
+ case "left":
31688
+ case "up":
31689
+ this.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1;
31690
+ break;
31691
+ case "down":
31692
+ case "right":
31693
+ this.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1;
31694
+ break;
31695
+ case "space":
31696
+ this.toggleValue();
31697
+ break;
31698
+ }
31699
+ });
31700
+ }
31701
+ get _value() {
31702
+ return this.options[this.cursor].value;
31703
+ }
31704
+ toggleAll() {
31705
+ const u = this.value.length === this.options.length;
31706
+ this.value = u ? [] : this.options.map((t) => t.value);
31707
+ }
31708
+ toggleValue() {
31709
+ const u = this.value.includes(this._value);
31710
+ this.value = u ? this.value.filter((t) => t !== this._value) : [...this.value, this._value];
31711
+ }
31712
+ };
31713
+ var OD = Object.defineProperty;
31714
+ var PD = (e, u, t) => (u in e) ? OD(e, u, { enumerable: true, configurable: true, writable: true, value: t }) : e[u] = t;
31715
+ var J = (e, u, t) => (PD(e, typeof u != "symbol" ? u + "" : u, t), t);
32478
31716
 
32479
- ### 2B.4 Create Plan
31717
+ class LD extends x {
31718
+ constructor(u) {
31719
+ super(u, false), J(this, "options"), J(this, "cursor", 0), this.options = u.options, this.cursor = this.options.findIndex(({ value: t }) => t === u.initialValue), this.cursor === -1 && (this.cursor = 0), this.changeValue(), this.on("cursor", (t) => {
31720
+ switch (t) {
31721
+ case "left":
31722
+ case "up":
31723
+ this.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1;
31724
+ break;
31725
+ case "down":
31726
+ case "right":
31727
+ this.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1;
31728
+ break;
31729
+ }
31730
+ this.changeValue();
31731
+ });
31732
+ }
31733
+ get _value() {
31734
+ return this.options[this.cursor];
31735
+ }
31736
+ changeValue() {
31737
+ this.value = this._value.value;
31738
+ }
31739
+ }
31740
+ class RD extends x {
31741
+ get valueWithCursor() {
31742
+ if (this.state === "submit")
31743
+ return this.value;
31744
+ if (this.cursor >= this.value.length)
31745
+ return `${this.value}█`;
31746
+ const u = this.value.slice(0, this.cursor), [t, ...F] = this.value.slice(this.cursor);
31747
+ return `${u}${import_picocolors.default.inverse(t)}${F.join("")}`;
31748
+ }
31749
+ get cursor() {
31750
+ return this._cursor;
31751
+ }
31752
+ constructor(u) {
31753
+ super(u), this.on("finalize", () => {
31754
+ this.value || (this.value = u.defaultValue);
31755
+ });
31756
+ }
31757
+ }
32480
31758
 
32481
- Call \`harmony_create_plan\` with:
32482
- - \`title\`: The plan title
32483
- - \`content\`: Full markdown document from Step 2B.3
32484
- - \`source\`: \`"agent"\`
32485
- - \`workflowPhase\`: \`"plan"\`
32486
- - \`tasks\`: Array of tasks from the Tasks section, each with:
32487
- - \`content\`: Task title + brief description
32488
- - \`priority\`: \`"high"\`, \`"medium"\`, or \`"low"\`
32489
- - \`status\`: \`"pending"\`
31759
+ // ../../node_modules/@clack/prompts/dist/index.mjs
31760
+ var import_picocolors2 = __toESM(require_picocolors(), 1);
31761
+ var import_sisteransi2 = __toESM(require_src(), 1);
31762
+ import y2 from "node:process";
31763
+ function ce() {
31764
+ return y2.platform !== "win32" ? y2.env.TERM !== "linux" : !!y2.env.CI || !!y2.env.WT_SESSION || !!y2.env.TERMINUS_SUBLIME || y2.env.ConEmuTask === "{cmd::Cmder}" || y2.env.TERM_PROGRAM === "Terminus-Sublime" || y2.env.TERM_PROGRAM === "vscode" || y2.env.TERM === "xterm-256color" || y2.env.TERM === "alacritty" || y2.env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
31765
+ }
31766
+ var V2 = ce();
31767
+ var u = (t, n) => V2 ? t : n;
31768
+ var le = u("◆", "*");
31769
+ var L2 = u("■", "x");
31770
+ var W2 = u("▲", "x");
31771
+ var C = u("◇", "o");
31772
+ var ue = u("┌", "T");
31773
+ var o = u("│", "|");
31774
+ var d2 = u("└", "—");
31775
+ var k2 = u("●", ">");
31776
+ var P2 = u("○", " ");
31777
+ var A2 = u("◻", "[•]");
31778
+ var T = u("◼", "[+]");
31779
+ var F = u("◻", "[ ]");
31780
+ var $e = u("▪", "•");
31781
+ var _2 = u("─", "-");
31782
+ var me = u("╮", "+");
31783
+ var de = u("├", "+");
31784
+ var pe = u("╯", "+");
31785
+ var q = u("●", "•");
31786
+ var D = u("◆", "*");
31787
+ var U = u("▲", "!");
31788
+ var K2 = u("■", "x");
31789
+ var b2 = (t) => {
31790
+ switch (t) {
31791
+ case "initial":
31792
+ case "active":
31793
+ return import_picocolors2.default.cyan(le);
31794
+ case "cancel":
31795
+ return import_picocolors2.default.red(L2);
31796
+ case "error":
31797
+ return import_picocolors2.default.yellow(W2);
31798
+ case "submit":
31799
+ return import_picocolors2.default.green(C);
31800
+ }
31801
+ };
31802
+ var G2 = (t) => {
31803
+ const { cursor: n, options: r2, style: i } = t, s = t.maxItems ?? Number.POSITIVE_INFINITY, c = Math.max(process.stdout.rows - 4, 0), a = Math.min(c, Math.max(s, 5));
31804
+ let l2 = 0;
31805
+ n >= l2 + a - 3 ? l2 = Math.max(Math.min(n - a + 3, r2.length - a), 0) : n < l2 + 2 && (l2 = Math.max(n - 2, 0));
31806
+ const $2 = a < r2.length && l2 > 0, g2 = a < r2.length && l2 + a < r2.length;
31807
+ return r2.slice(l2, l2 + a).map((p2, v2, f) => {
31808
+ const j2 = v2 === 0 && $2, E = v2 === f.length - 1 && g2;
31809
+ return j2 || E ? import_picocolors2.default.dim("...") : i(p2, v2 + l2 === n);
31810
+ });
31811
+ };
31812
+ var he = (t) => new RD({ validate: t.validate, placeholder: t.placeholder, defaultValue: t.defaultValue, initialValue: t.initialValue, render() {
31813
+ const n = `${import_picocolors2.default.gray(o)}
31814
+ ${b2(this.state)} ${t.message}
31815
+ `, r2 = t.placeholder ? import_picocolors2.default.inverse(t.placeholder[0]) + import_picocolors2.default.dim(t.placeholder.slice(1)) : import_picocolors2.default.inverse(import_picocolors2.default.hidden("_")), i = this.value ? this.valueWithCursor : r2;
31816
+ switch (this.state) {
31817
+ case "error":
31818
+ return `${n.trim()}
31819
+ ${import_picocolors2.default.yellow(o)} ${i}
31820
+ ${import_picocolors2.default.yellow(d2)} ${import_picocolors2.default.yellow(this.error)}
31821
+ `;
31822
+ case "submit":
31823
+ return `${n}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.dim(this.value || t.placeholder)}`;
31824
+ case "cancel":
31825
+ return `${n}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(this.value ?? ""))}${this.value?.trim() ? `
31826
+ ${import_picocolors2.default.gray(o)}` : ""}`;
31827
+ default:
31828
+ return `${n}${import_picocolors2.default.cyan(o)} ${i}
31829
+ ${import_picocolors2.default.cyan(d2)}
31830
+ `;
31831
+ }
31832
+ } }).prompt();
31833
+ var ye = (t) => {
31834
+ const n = t.active ?? "Yes", r2 = t.inactive ?? "No";
31835
+ return new dD({ active: n, inactive: r2, initialValue: t.initialValue ?? true, render() {
31836
+ const i = `${import_picocolors2.default.gray(o)}
31837
+ ${b2(this.state)} ${t.message}
31838
+ `, s = this.value ? n : r2;
31839
+ switch (this.state) {
31840
+ case "submit":
31841
+ return `${i}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.dim(s)}`;
31842
+ case "cancel":
31843
+ return `${i}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(s))}
31844
+ ${import_picocolors2.default.gray(o)}`;
31845
+ default:
31846
+ return `${i}${import_picocolors2.default.cyan(o)} ${this.value ? `${import_picocolors2.default.green(k2)} ${n}` : `${import_picocolors2.default.dim(P2)} ${import_picocolors2.default.dim(n)}`} ${import_picocolors2.default.dim("/")} ${this.value ? `${import_picocolors2.default.dim(P2)} ${import_picocolors2.default.dim(r2)}` : `${import_picocolors2.default.green(k2)} ${r2}`}
31847
+ ${import_picocolors2.default.cyan(d2)}
31848
+ `;
31849
+ }
31850
+ } }).prompt();
31851
+ };
31852
+ var ve = (t) => {
31853
+ const n = (r2, i) => {
31854
+ const s = r2.label ?? String(r2.value);
31855
+ switch (i) {
31856
+ case "selected":
31857
+ return `${import_picocolors2.default.dim(s)}`;
31858
+ case "active":
31859
+ return `${import_picocolors2.default.green(k2)} ${s} ${r2.hint ? import_picocolors2.default.dim(`(${r2.hint})`) : ""}`;
31860
+ case "cancelled":
31861
+ return `${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(s))}`;
31862
+ default:
31863
+ return `${import_picocolors2.default.dim(P2)} ${import_picocolors2.default.dim(s)}`;
31864
+ }
31865
+ };
31866
+ return new LD({ options: t.options, initialValue: t.initialValue, render() {
31867
+ const r2 = `${import_picocolors2.default.gray(o)}
31868
+ ${b2(this.state)} ${t.message}
31869
+ `;
31870
+ switch (this.state) {
31871
+ case "submit":
31872
+ return `${r2}${import_picocolors2.default.gray(o)} ${n(this.options[this.cursor], "selected")}`;
31873
+ case "cancel":
31874
+ return `${r2}${import_picocolors2.default.gray(o)} ${n(this.options[this.cursor], "cancelled")}
31875
+ ${import_picocolors2.default.gray(o)}`;
31876
+ default:
31877
+ return `${r2}${import_picocolors2.default.cyan(o)} ${G2({ cursor: this.cursor, options: this.options, maxItems: t.maxItems, style: (i, s) => n(i, s ? "active" : "inactive") }).join(`
31878
+ ${import_picocolors2.default.cyan(o)} `)}
31879
+ ${import_picocolors2.default.cyan(d2)}
31880
+ `;
31881
+ }
31882
+ } }).prompt();
31883
+ };
31884
+ var fe = (t) => {
31885
+ const n = (r2, i) => {
31886
+ const s = r2.label ?? String(r2.value);
31887
+ return i === "active" ? `${import_picocolors2.default.cyan(A2)} ${s} ${r2.hint ? import_picocolors2.default.dim(`(${r2.hint})`) : ""}` : i === "selected" ? `${import_picocolors2.default.green(T)} ${import_picocolors2.default.dim(s)} ${r2.hint ? import_picocolors2.default.dim(`(${r2.hint})`) : ""}` : i === "cancelled" ? `${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(s))}` : i === "active-selected" ? `${import_picocolors2.default.green(T)} ${s} ${r2.hint ? import_picocolors2.default.dim(`(${r2.hint})`) : ""}` : i === "submitted" ? `${import_picocolors2.default.dim(s)}` : `${import_picocolors2.default.dim(F)} ${import_picocolors2.default.dim(s)}`;
31888
+ };
31889
+ return new SD({ options: t.options, initialValues: t.initialValues, required: t.required ?? true, cursorAt: t.cursorAt, validate(r2) {
31890
+ if (this.required && r2.length === 0)
31891
+ return `Please select at least one option.
31892
+ ${import_picocolors2.default.reset(import_picocolors2.default.dim(`Press ${import_picocolors2.default.gray(import_picocolors2.default.bgWhite(import_picocolors2.default.inverse(" space ")))} to select, ${import_picocolors2.default.gray(import_picocolors2.default.bgWhite(import_picocolors2.default.inverse(" enter ")))} to submit`))}`;
31893
+ }, render() {
31894
+ const r2 = `${import_picocolors2.default.gray(o)}
31895
+ ${b2(this.state)} ${t.message}
31896
+ `, i = (s, c) => {
31897
+ const a = this.value.includes(s.value);
31898
+ return c && a ? n(s, "active-selected") : a ? n(s, "selected") : n(s, c ? "active" : "inactive");
31899
+ };
31900
+ switch (this.state) {
31901
+ case "submit":
31902
+ return `${r2}${import_picocolors2.default.gray(o)} ${this.options.filter(({ value: s }) => this.value.includes(s)).map((s) => n(s, "submitted")).join(import_picocolors2.default.dim(", ")) || import_picocolors2.default.dim("none")}`;
31903
+ case "cancel": {
31904
+ const s = this.options.filter(({ value: c }) => this.value.includes(c)).map((c) => n(c, "cancelled")).join(import_picocolors2.default.dim(", "));
31905
+ return `${r2}${import_picocolors2.default.gray(o)} ${s.trim() ? `${s}
31906
+ ${import_picocolors2.default.gray(o)}` : ""}`;
31907
+ }
31908
+ case "error": {
31909
+ const s = this.error.split(`
31910
+ `).map((c, a) => a === 0 ? `${import_picocolors2.default.yellow(d2)} ${import_picocolors2.default.yellow(c)}` : ` ${c}`).join(`
31911
+ `);
31912
+ return `${r2 + import_picocolors2.default.yellow(o)} ${G2({ options: this.options, cursor: this.cursor, maxItems: t.maxItems, style: i }).join(`
31913
+ ${import_picocolors2.default.yellow(o)} `)}
31914
+ ${s}
31915
+ `;
31916
+ }
31917
+ default:
31918
+ return `${r2}${import_picocolors2.default.cyan(o)} ${G2({ options: this.options, cursor: this.cursor, maxItems: t.maxItems, style: i }).join(`
31919
+ ${import_picocolors2.default.cyan(o)} `)}
31920
+ ${import_picocolors2.default.cyan(d2)}
31921
+ `;
31922
+ }
31923
+ } }).prompt();
31924
+ };
31925
+ var xe = (t = "") => {
31926
+ process.stdout.write(`${import_picocolors2.default.gray(d2)} ${import_picocolors2.default.red(t)}
32490
31927
 
32491
- ### 2B.5 — User Approval
31928
+ `);
31929
+ };
31930
+ var Se = (t = "") => {
31931
+ process.stdout.write(`${import_picocolors2.default.gray(o)}
31932
+ ${import_picocolors2.default.gray(d2)} ${t}
32492
31933
 
32493
- Show the user:
32494
- - Plan URL: \`https://gethmy.com/plans/{id}\`
32495
- - Number of tasks created
32496
- - Brief summary
31934
+ `);
31935
+ };
31936
+ var M2 = { message: (t = "", { symbol: n = import_picocolors2.default.gray(o) } = {}) => {
31937
+ const r2 = [`${import_picocolors2.default.gray(o)}`];
31938
+ if (t) {
31939
+ const [i, ...s] = t.split(`
31940
+ `);
31941
+ r2.push(`${n} ${i}`, ...s.map((c) => `${import_picocolors2.default.gray(o)} ${c}`));
31942
+ }
31943
+ process.stdout.write(`${r2.join(`
31944
+ `)}
31945
+ `);
31946
+ }, info: (t) => {
31947
+ M2.message(t, { symbol: import_picocolors2.default.blue(q) });
31948
+ }, success: (t) => {
31949
+ M2.message(t, { symbol: import_picocolors2.default.green(D) });
31950
+ }, step: (t) => {
31951
+ M2.message(t, { symbol: import_picocolors2.default.green(C) });
31952
+ }, warn: (t) => {
31953
+ M2.message(t, { symbol: import_picocolors2.default.yellow(U) });
31954
+ }, warning: (t) => {
31955
+ M2.warn(t);
31956
+ }, error: (t) => {
31957
+ M2.message(t, { symbol: import_picocolors2.default.red(K2) });
31958
+ } };
31959
+ var J2 = `${import_picocolors2.default.gray(o)} `;
31960
+ var Y2 = ({ indicator: t = "dots" } = {}) => {
31961
+ const n = V2 ? ["◒", "◐", "◓", "◑"] : ["•", "o", "O", "0"], r2 = V2 ? 80 : 120, i = process.env.CI === "true";
31962
+ let s, c, a = false, l2 = "", $2, g2 = performance.now();
31963
+ const p2 = (m2) => {
31964
+ const h2 = m2 > 1 ? "Something went wrong" : "Canceled";
31965
+ a && N2(h2, m2);
31966
+ }, v2 = () => p2(2), f = () => p2(1), j2 = () => {
31967
+ process.on("uncaughtExceptionMonitor", v2), process.on("unhandledRejection", v2), process.on("SIGINT", f), process.on("SIGTERM", f), process.on("exit", p2);
31968
+ }, E = () => {
31969
+ process.removeListener("uncaughtExceptionMonitor", v2), process.removeListener("unhandledRejection", v2), process.removeListener("SIGINT", f), process.removeListener("SIGTERM", f), process.removeListener("exit", p2);
31970
+ }, B2 = () => {
31971
+ if ($2 === undefined)
31972
+ return;
31973
+ i && process.stdout.write(`
31974
+ `);
31975
+ const m2 = $2.split(`
31976
+ `);
31977
+ process.stdout.write(import_sisteransi2.cursor.move(-999, m2.length - 1)), process.stdout.write(import_sisteransi2.erase.down(m2.length));
31978
+ }, R2 = (m2) => m2.replace(/\.+$/, ""), O2 = (m2) => {
31979
+ const h2 = (performance.now() - m2) / 1000, w2 = Math.floor(h2 / 60), I2 = Math.floor(h2 % 60);
31980
+ return w2 > 0 ? `[${w2}m ${I2}s]` : `[${I2}s]`;
31981
+ }, H2 = (m2 = "") => {
31982
+ a = true, s = fD(), l2 = R2(m2), g2 = performance.now(), process.stdout.write(`${import_picocolors2.default.gray(o)}
31983
+ `);
31984
+ let h2 = 0, w2 = 0;
31985
+ j2(), c = setInterval(() => {
31986
+ if (i && l2 === $2)
31987
+ return;
31988
+ B2(), $2 = l2;
31989
+ const I2 = import_picocolors2.default.magenta(n[h2]);
31990
+ if (i)
31991
+ process.stdout.write(`${I2} ${l2}...`);
31992
+ else if (t === "timer")
31993
+ process.stdout.write(`${I2} ${l2} ${O2(g2)}`);
31994
+ else {
31995
+ const z3 = ".".repeat(Math.floor(w2)).slice(0, 3);
31996
+ process.stdout.write(`${I2} ${l2}${z3}`);
31997
+ }
31998
+ h2 = h2 + 1 < n.length ? h2 + 1 : 0, w2 = w2 < n.length ? w2 + 0.125 : 0;
31999
+ }, r2);
32000
+ }, N2 = (m2 = "", h2 = 0) => {
32001
+ a = false, clearInterval(c), B2();
32002
+ const w2 = h2 === 0 ? import_picocolors2.default.green(C) : h2 === 1 ? import_picocolors2.default.red(L2) : import_picocolors2.default.red(W2);
32003
+ l2 = R2(m2 ?? l2), t === "timer" ? process.stdout.write(`${w2} ${l2} ${O2(g2)}
32004
+ `) : process.stdout.write(`${w2} ${l2}
32005
+ `), E(), s();
32006
+ };
32007
+ return { start: H2, stop: N2, message: (m2 = "") => {
32008
+ l2 = R2(m2 ?? l2);
32009
+ } };
32010
+ };
32497
32011
 
32498
- Then ask: **"Ready to execute? I'll create board cards from these tasks and start the execution phase."**
32012
+ // src/tui/agents.ts
32013
+ import { existsSync as existsSync4 } from "node:fs";
32014
+ import { homedir as homedir2 } from "node:os";
32015
+ import { join as join3 } from "node:path";
32016
+ var AGENT_DEFINITIONS = [
32017
+ {
32018
+ id: "claude",
32019
+ name: "Claude Code",
32020
+ description: "Anthropic CLI agent",
32021
+ hint: "/hmy <card>",
32022
+ globalPaths: [join3(homedir2(), ".claude")],
32023
+ localPaths: [".claude"]
32024
+ },
32025
+ {
32026
+ id: "codex",
32027
+ name: "Codex",
32028
+ description: "OpenAI coding agent",
32029
+ hint: "/prompts:hmy <card>",
32030
+ globalPaths: [join3(homedir2(), ".codex")],
32031
+ localPaths: ["AGENTS.md"]
32032
+ },
32033
+ {
32034
+ id: "cursor",
32035
+ name: "Cursor",
32036
+ description: "AI-powered IDE",
32037
+ hint: "MCP tools available automatically",
32038
+ globalPaths: [],
32039
+ localPaths: [".cursor", ".cursorrules"]
32040
+ },
32041
+ {
32042
+ id: "windsurf",
32043
+ name: "Windsurf",
32044
+ description: "Codeium AI IDE",
32045
+ hint: "MCP tools available automatically",
32046
+ globalPaths: [join3(homedir2(), ".codeium", "windsurf")],
32047
+ localPaths: [".windsurf", ".windsurfrules"]
32048
+ }
32049
+ ];
32050
+ function detectAgents(cwd = process.cwd()) {
32051
+ return AGENT_DEFINITIONS.map((def) => {
32052
+ const globalPath = def.globalPaths.find((p2) => existsSync4(p2)) || null;
32053
+ const localPath = def.localPaths.find((p2) => existsSync4(join3(cwd, p2))) || null;
32054
+ return {
32055
+ id: def.id,
32056
+ name: def.name,
32057
+ detected: !!(globalPath || localPath),
32058
+ globalPath,
32059
+ localPath: localPath ? join3(cwd, localPath) : null,
32060
+ description: def.description,
32061
+ hint: def.hint
32062
+ };
32063
+ });
32064
+ }
32499
32065
 
32500
- Options:
32501
- 1. **Yes, advance to Execute** proceed to Step 2B.6
32502
- 2. **Let me review first** end here, they can advance later from the UI
32503
- 3. **Make changes** — iterate on the plan
32066
+ // src/tui/docs.ts
32067
+ import { existsSync as existsSync5, readdirSync as readdirSync2, readFileSync as readFileSync4, statSync } from "node:fs";
32068
+ import { isAbsolute, join as join4, resolve, sep as sep2 } from "node:path";
32504
32069
 
32505
- ### 2B.6 — Advance to Execute
32070
+ // src/tui/theme.ts
32071
+ var pc = __toESM(require_picocolors(), 1);
32072
+ var symbols = {
32073
+ harmony: "▲",
32074
+ check: "✓",
32075
+ cross: "✗",
32076
+ bullet: "•",
32077
+ arrow: "→",
32078
+ arrowRight: "▸",
32079
+ dot: "●",
32080
+ dotEmpty: "○",
32081
+ info: "ℹ",
32082
+ warning: "⚠",
32083
+ pointer: "❯"
32084
+ };
32085
+ var colors = {
32086
+ brand: (text) => pc.cyan(text),
32087
+ brandBold: (text) => pc.bold(pc.cyan(text)),
32088
+ success: (text) => pc.green(text),
32089
+ error: (text) => pc.red(text),
32090
+ warning: (text) => pc.yellow(text),
32091
+ info: (text) => pc.blue(text),
32092
+ dim: (text) => pc.dim(text),
32093
+ bold: (text) => pc.bold(text),
32094
+ muted: (text) => pc.gray(text),
32095
+ highlight: (text) => pc.cyan(text),
32096
+ link: (text) => pc.underline(pc.cyan(text))
32097
+ };
32098
+ var messages = {
32099
+ header: () => {
32100
+ return `
32101
+ ${colors.brandBold(" HARMONY")}
32102
+ ${colors.dim(" Project management for AI agents")}
32103
+ `;
32104
+ },
32105
+ done: (message) => {
32106
+ return `${colors.success(symbols.check)} ${message}`;
32107
+ },
32108
+ fail: (message) => {
32109
+ return `${colors.error(symbols.cross)} ${message}`;
32110
+ },
32111
+ skip: (message) => {
32112
+ return `${colors.dim("-")} ${colors.dim(message)}`;
32113
+ },
32114
+ step: (number5, total, message) => {
32115
+ return `${colors.dim(`[${number5}/${total}]`)} ${message}`;
32116
+ },
32117
+ fileCreated: (path) => {
32118
+ return ` ${colors.success(symbols.check)} ${colors.dim(path)}`;
32119
+ },
32120
+ fileSkipped: (path) => {
32121
+ return ` ${colors.dim(symbols.bullet)} ${colors.dim(path)} ${colors.dim("(exists)")}`;
32122
+ },
32123
+ fileError: (path, error48) => {
32124
+ return ` ${colors.error(symbols.cross)} ${path}: ${colors.error(error48)}`;
32125
+ }
32126
+ };
32127
+ function formatPath(path, homeDir) {
32128
+ if (path.startsWith(homeDir)) {
32129
+ return `~${path.slice(homeDir.length)}`;
32130
+ }
32131
+ return path;
32132
+ }
32506
32133
 
32507
- Call \`harmony_advance_plan\` with:
32508
- - \`planId\`: The plan ID from Step 2B.4
32509
- - \`phase\`: \`"execute"\`
32510
- - \`summary\`: A 2-3 sentence summary of the key decisions made during planning
32134
+ // src/tui/docs.ts
32135
+ var IGNORED_DIRS = new Set([
32136
+ "node_modules",
32137
+ ".git",
32138
+ "dist",
32139
+ "build",
32140
+ ".next",
32141
+ ".nuxt",
32142
+ ".output",
32143
+ ".vercel",
32144
+ ".turbo",
32145
+ ".cache",
32146
+ "coverage",
32147
+ ".harmony-worktrees",
32148
+ "__pycache__",
32149
+ "target",
32150
+ "vendor"
32151
+ ]);
32152
+ function readJson(filePath) {
32153
+ try {
32154
+ return JSON.parse(readFileSync4(filePath, "utf-8"));
32155
+ } catch {
32156
+ return null;
32157
+ }
32158
+ }
32159
+ function readText(filePath) {
32160
+ try {
32161
+ return readFileSync4(filePath, "utf-8");
32162
+ } catch {
32163
+ return null;
32164
+ }
32165
+ }
32166
+ function listDirs(dirPath) {
32167
+ try {
32168
+ return readdirSync2(dirPath).filter((entry) => {
32169
+ if (IGNORED_DIRS.has(entry) || entry.startsWith("."))
32170
+ return false;
32171
+ try {
32172
+ return statSync(join4(dirPath, entry)).isDirectory();
32173
+ } catch {
32174
+ return false;
32175
+ }
32176
+ });
32177
+ } catch {
32178
+ return [];
32179
+ }
32180
+ }
32181
+ var DIR_DESCRIPTIONS = {
32182
+ components: "UI components",
32183
+ pages: "Route-level pages",
32184
+ routes: "Route-level pages",
32185
+ views: "Route-level pages",
32186
+ hooks: "Custom hooks",
32187
+ lib: "Utilities",
32188
+ utils: "Utilities",
32189
+ api: "API / server code",
32190
+ server: "API / server code",
32191
+ contexts: "State management",
32192
+ store: "State management",
32193
+ stores: "State management",
32194
+ types: "Type definitions",
32195
+ styles: "Stylesheets",
32196
+ public: "Static assets",
32197
+ static: "Static assets",
32198
+ assets: "Static assets",
32199
+ supabase: "Supabase backend",
32200
+ functions: "Edge functions",
32201
+ packages: "Monorepo packages",
32202
+ apps: "Monorepo applications",
32203
+ src: "Source code",
32204
+ test: "Tests",
32205
+ tests: "Tests",
32206
+ __tests__: "Tests",
32207
+ scripts: "Build / utility scripts",
32208
+ config: "Configuration",
32209
+ docs: "Documentation",
32210
+ migrations: "Database migrations",
32211
+ prisma: "Prisma schema & migrations",
32212
+ e2e: "End-to-end tests",
32213
+ cypress: "Cypress tests"
32214
+ };
32215
+ function describeDir(name) {
32216
+ return DIR_DESCRIPTIONS[name.toLowerCase()] ?? name;
32217
+ }
32218
+ function scanProject(cwd) {
32219
+ let packageManager = null;
32220
+ if (existsSync5(join4(cwd, "bun.lock")) || existsSync5(join4(cwd, "bun.lockb"))) {
32221
+ packageManager = "bun";
32222
+ } else if (existsSync5(join4(cwd, "pnpm-lock.yaml"))) {
32223
+ packageManager = "pnpm";
32224
+ } else if (existsSync5(join4(cwd, "yarn.lock"))) {
32225
+ packageManager = "yarn";
32226
+ } else if (existsSync5(join4(cwd, "package.json"))) {
32227
+ packageManager = "npm";
32228
+ }
32229
+ const pkg = readJson(join4(cwd, "package.json"));
32230
+ const scripts = pkg && typeof pkg.scripts === "object" && pkg.scripts !== null ? pkg.scripts : {};
32231
+ let language = "unknown";
32232
+ if (existsSync5(join4(cwd, "tsconfig.json"))) {
32233
+ language = "typescript";
32234
+ } else if (existsSync5(join4(cwd, "go.mod"))) {
32235
+ language = "go";
32236
+ } else if (existsSync5(join4(cwd, "Cargo.toml"))) {
32237
+ language = "rust";
32238
+ } else if (existsSync5(join4(cwd, "setup.py")) || existsSync5(join4(cwd, "pyproject.toml"))) {
32239
+ language = "python";
32240
+ } else if (pkg) {
32241
+ language = "javascript";
32242
+ }
32243
+ let framework = null;
32244
+ if (pkg) {
32245
+ const deps = {
32246
+ ...typeof pkg.dependencies === "object" ? pkg.dependencies : {},
32247
+ ...typeof pkg.devDependencies === "object" ? pkg.devDependencies : {}
32248
+ };
32249
+ if (deps.next) {
32250
+ framework = "next";
32251
+ } else if (deps.react && deps.vite) {
32252
+ framework = "react+vite";
32253
+ } else if (deps.react) {
32254
+ framework = "react";
32255
+ } else if (deps.vue && deps.vite) {
32256
+ framework = "vue+vite";
32257
+ } else if (deps.vue && deps.nuxt) {
32258
+ framework = "nuxt";
32259
+ } else if (deps.vue) {
32260
+ framework = "vue";
32261
+ } else if (deps.astro) {
32262
+ framework = "astro";
32263
+ } else if (deps.svelte) {
32264
+ framework = "svelte";
32265
+ } else if (deps.express) {
32266
+ framework = "express";
32267
+ } else if (deps.fastify) {
32268
+ framework = "fastify";
32269
+ } else if (deps.hono) {
32270
+ framework = "hono";
32271
+ }
32272
+ }
32273
+ let linter = null;
32274
+ if (existsSync5(join4(cwd, "biome.json")) || existsSync5(join4(cwd, "biome.jsonc"))) {
32275
+ linter = "biome";
32276
+ } else {
32277
+ const eslintFiles = [
32278
+ ".eslintrc",
32279
+ ".eslintrc.js",
32280
+ ".eslintrc.cjs",
32281
+ ".eslintrc.json",
32282
+ ".eslintrc.yml",
32283
+ ".eslintrc.yaml",
32284
+ "eslint.config.js",
32285
+ "eslint.config.mjs",
32286
+ "eslint.config.cjs",
32287
+ "eslint.config.ts"
32288
+ ];
32289
+ if (eslintFiles.some((f) => existsSync5(join4(cwd, f)))) {
32290
+ linter = "eslint";
32291
+ } else {
32292
+ const prettierFiles = [
32293
+ ".prettierrc",
32294
+ ".prettierrc.js",
32295
+ ".prettierrc.json",
32296
+ ".prettierrc.yml",
32297
+ ".prettierrc.yaml",
32298
+ "prettier.config.js",
32299
+ "prettier.config.mjs"
32300
+ ];
32301
+ if (prettierFiles.some((f) => existsSync5(join4(cwd, f)))) {
32302
+ linter = "prettier";
32303
+ }
32304
+ }
32305
+ }
32306
+ let indentStyle = null;
32307
+ const biome = readJson(join4(cwd, "biome.json")) ?? readJson(join4(cwd, "biome.jsonc"));
32308
+ if (biome) {
32309
+ const formatter = biome.formatter;
32310
+ if (formatter) {
32311
+ const type = formatter.indentStyle === "tab" ? "tab" : "space";
32312
+ const width = typeof formatter.indentWidth === "number" ? formatter.indentWidth : 2;
32313
+ indentStyle = { type, width };
32314
+ }
32315
+ }
32316
+ if (!indentStyle) {
32317
+ const editorConfig = readText(join4(cwd, ".editorconfig"));
32318
+ if (editorConfig) {
32319
+ const styleMatch = editorConfig.match(/indent_style\s*=\s*(space|tab)/);
32320
+ const sizeMatch = editorConfig.match(/indent_size\s*=\s*(\d+)/);
32321
+ if (styleMatch) {
32322
+ indentStyle = {
32323
+ type: styleMatch[1],
32324
+ width: sizeMatch ? Number.parseInt(sizeMatch[1], 10) : 2
32325
+ };
32326
+ }
32327
+ }
32328
+ }
32329
+ const dirs = listDirs(cwd);
32330
+ const srcDirs = existsSync5(join4(cwd, "src")) ? listDirs(join4(cwd, "src")) : [];
32331
+ const monorepo = existsSync5(join4(cwd, "packages")) || existsSync5(join4(cwd, "apps"));
32332
+ const existingDocs = {
32333
+ agentsMd: existsSync5(join4(cwd, "AGENTS.md")),
32334
+ claudeMd: existsSync5(join4(cwd, "CLAUDE.md")),
32335
+ docsDir: existsSync5(join4(cwd, "docs")),
32336
+ architectureMd: existsSync5(join4(cwd, "docs", "architecture.md"))
32337
+ };
32338
+ return {
32339
+ packageManager,
32340
+ scripts,
32341
+ language,
32342
+ framework,
32343
+ linter,
32344
+ indentStyle,
32345
+ dirs,
32346
+ srcDirs,
32347
+ monorepo,
32348
+ existingDocs
32349
+ };
32350
+ }
32351
+ function runCmd(pm) {
32352
+ if (pm === "bun")
32353
+ return "bun run";
32354
+ if (pm === "pnpm")
32355
+ return "pnpm run";
32356
+ if (pm === "yarn")
32357
+ return "yarn";
32358
+ return "npm run";
32359
+ }
32360
+ function describeScript(name) {
32361
+ const map3 = {
32362
+ dev: "Dev server",
32363
+ start: "Start server",
32364
+ build: "Production build",
32365
+ lint: "Lint",
32366
+ "lint:fix": "Lint + autofix",
32367
+ format: "Format code",
32368
+ test: "Run tests",
32369
+ "test:watch": "Run tests (watch)",
32370
+ "test:e2e": "End-to-end tests",
32371
+ typecheck: "Type-check",
32372
+ "type-check": "Type-check",
32373
+ preview: "Preview production build",
32374
+ deploy: "Deploy",
32375
+ generate: "Code generation",
32376
+ migrate: "Run migrations",
32377
+ seed: "Seed database",
32378
+ clean: "Clean build artifacts",
32379
+ prepare: "Prepare (husky, etc.)"
32380
+ };
32381
+ return map3[name] ?? "";
32382
+ }
32383
+ function generateAgentsMd(info, _cwd) {
32384
+ const lang = info.language === "typescript" ? "TypeScript" : info.language === "javascript" ? "JavaScript" : info.language;
32385
+ const frameworkLabel = info.framework ? `${info.framework} ` : "";
32386
+ const monoLabel = info.monorepo ? " (monorepo)" : "";
32387
+ const lines = [];
32388
+ lines.push("# AGENTS.md");
32389
+ lines.push("");
32390
+ lines.push(`${frameworkLabel}${lang} project${monoLabel}.`);
32391
+ lines.push("");
32392
+ const scriptEntries = Object.entries(info.scripts);
32393
+ if (scriptEntries.length > 0 && info.packageManager) {
32394
+ const prefix = runCmd(info.packageManager);
32395
+ lines.push("## Commands");
32396
+ lines.push("");
32397
+ lines.push("```bash");
32398
+ const commands = scriptEntries.map(([name]) => `${prefix} ${name}`);
32399
+ const maxLen = Math.max(...commands.map((c) => c.length));
32400
+ for (let i = 0;i < scriptEntries.length; i++) {
32401
+ const [name] = scriptEntries[i];
32402
+ const cmd = commands[i];
32403
+ const desc = describeScript(name);
32404
+ if (desc) {
32405
+ lines.push(`${cmd}${" ".repeat(maxLen - cmd.length + 4)}# ${desc}`);
32406
+ } else {
32407
+ lines.push(cmd);
32408
+ }
32409
+ }
32410
+ lines.push("```");
32411
+ lines.push("");
32412
+ }
32413
+ lines.push("## Code Standards");
32414
+ lines.push("");
32415
+ const langLabel = info.language === "typescript" ? "TypeScript" : "JavaScript";
32416
+ if (info.language === "typescript" || info.language === "javascript") {
32417
+ lines.push(`- ${langLabel} with ES modules`);
32418
+ }
32419
+ if (info.indentStyle) {
32420
+ const unit = info.indentStyle.type === "tab" ? "tab" : "space";
32421
+ lines.push(`- ${info.indentStyle.width}-${unit} indentation`);
32422
+ }
32423
+ if (info.linter) {
32424
+ lines.push(`- Linted with ${info.linter}`);
32425
+ }
32426
+ lines.push("");
32427
+ lines.push("## Architecture");
32428
+ lines.push("");
32429
+ for (const dir of info.dirs) {
32430
+ lines.push(`- \`${dir}/\` — ${describeDir(dir)}`);
32431
+ }
32432
+ if (info.srcDirs.length > 0) {
32433
+ for (const sub of info.srcDirs) {
32434
+ lines.push(` - \`src/${sub}/\` — ${describeDir(sub)}`);
32435
+ }
32436
+ }
32437
+ lines.push("");
32438
+ return lines.join(`
32439
+ `);
32440
+ }
32441
+ function generateClaudeMd(info) {
32442
+ const lines = [];
32443
+ lines.push("# CLAUDE.md");
32444
+ lines.push("");
32445
+ lines.push("@AGENTS.md");
32446
+ if (info.existingDocs.architectureMd || info.dirs.includes("docs")) {
32447
+ lines.push("@docs/architecture.md");
32448
+ }
32449
+ lines.push("");
32450
+ return lines.join(`
32451
+ `);
32452
+ }
32453
+ function generateArchitectureMd(info, _cwd) {
32454
+ const lines = [];
32455
+ lines.push("# Architecture");
32456
+ lines.push("");
32457
+ lines.push("## Directory Structure");
32458
+ lines.push("");
32459
+ for (const dir of info.dirs) {
32460
+ lines.push(`- \`${dir}/\` — ${describeDir(dir)}`);
32461
+ }
32462
+ if (info.srcDirs.length > 0) {
32463
+ lines.push("");
32464
+ lines.push("### `src/`");
32465
+ lines.push("");
32466
+ for (const sub of info.srcDirs) {
32467
+ lines.push(`- \`src/${sub}/\` — ${describeDir(sub)}`);
32468
+ }
32469
+ }
32470
+ lines.push("");
32471
+ return lines.join(`
32472
+ `);
32473
+ }
32474
+ var VAGUE_STANDARDS = [
32475
+ "follow best practices",
32476
+ "use best practices",
32477
+ "keep it clean",
32478
+ "write clean code",
32479
+ "maintain code quality",
32480
+ "ensure quality",
32481
+ "use proper naming",
32482
+ "follow conventions",
32483
+ "be consistent"
32484
+ ];
32485
+ function verifyDocs(cwd) {
32486
+ const issues = [];
32487
+ const claudeMd = readText(join4(cwd, "CLAUDE.md"));
32488
+ const agentsMd = readText(join4(cwd, "AGENTS.md"));
32489
+ const pkg = readJson(join4(cwd, "package.json"));
32490
+ const pkgScripts = pkg && typeof pkg.scripts === "object" && pkg.scripts !== null ? pkg.scripts : {};
32491
+ const projectRoot = resolve(cwd);
32492
+ if (claudeMd) {
32493
+ const importedFiles = [];
32494
+ for (const line of claudeMd.split(`
32495
+ `)) {
32496
+ const match = line.match(/^@(.+)$/);
32497
+ if (match) {
32498
+ const refPath = match[1].trim();
32499
+ if (isAbsolute(refPath)) {
32500
+ issues.push({
32501
+ severity: "error",
32502
+ file: "CLAUDE.md",
32503
+ message: `@ reference uses an absolute path: ${refPath}`,
32504
+ fix: "Use a project-relative path under the repository root"
32505
+ });
32506
+ continue;
32507
+ }
32508
+ const resolvedPath = resolve(projectRoot, refPath);
32509
+ if (resolvedPath !== projectRoot && !resolvedPath.startsWith(projectRoot + sep2)) {
32510
+ issues.push({
32511
+ severity: "error",
32512
+ file: "CLAUDE.md",
32513
+ message: `@ reference escapes project root: ${refPath}`,
32514
+ fix: "Remove traversal segments (../) and keep references inside the repo"
32515
+ });
32516
+ continue;
32517
+ }
32518
+ importedFiles.push({ ref: refPath, resolved: resolvedPath });
32519
+ if (!existsSync5(resolvedPath)) {
32520
+ issues.push({
32521
+ severity: "error",
32522
+ file: "CLAUDE.md",
32523
+ message: `Referenced file does not exist: ${refPath}`,
32524
+ fix: `Remove the @${refPath} line or create the file`
32525
+ });
32526
+ }
32527
+ }
32528
+ }
32529
+ const claudeLines = claudeMd.split(`
32530
+ `).length;
32531
+ if (claudeLines > 100) {
32532
+ issues.push({
32533
+ severity: "warning",
32534
+ file: "CLAUDE.md",
32535
+ message: `CLAUDE.md is ${claudeLines} lines (recommended: under 100)`,
32536
+ fix: "Move detailed content to AGENTS.md or docs/ files and use @imports"
32537
+ });
32538
+ }
32539
+ if (importedFiles.length > 0) {
32540
+ const claudeHeadings = extractHeadings(claudeMd);
32541
+ for (const { ref: refPath, resolved: resolvedPath } of importedFiles) {
32542
+ const refContent = readText(resolvedPath);
32543
+ if (!refContent)
32544
+ continue;
32545
+ const refHeadings = extractHeadings(refContent);
32546
+ for (const heading of claudeHeadings) {
32547
+ if (refHeadings.has(heading)) {
32548
+ issues.push({
32549
+ severity: "warning",
32550
+ file: "CLAUDE.md",
32551
+ message: `Section "${heading}" duplicates content from @${refPath}`,
32552
+ fix: `Remove the "${heading}" section — it's already included via @import`
32553
+ });
32554
+ }
32555
+ }
32556
+ }
32557
+ }
32558
+ }
32559
+ if (agentsMd) {
32560
+ const agentsLines = agentsMd.split(`
32561
+ `);
32562
+ const contextLines = [];
32563
+ let pastFirstHeading = false;
32564
+ let hitNextSection = false;
32565
+ for (const line of agentsLines) {
32566
+ if (!pastFirstHeading) {
32567
+ if (line.startsWith("# ")) {
32568
+ pastFirstHeading = true;
32569
+ }
32570
+ continue;
32571
+ }
32572
+ if (line.startsWith("## ")) {
32573
+ hitNextSection = true;
32574
+ break;
32575
+ }
32576
+ const trimmed = line.trim();
32577
+ if (trimmed)
32578
+ contextLines.push(trimmed);
32579
+ }
32580
+ if (pastFirstHeading && !hitNextSection && contextLines.length === 0) {
32581
+ issues.push({
32582
+ severity: "warning",
32583
+ file: "AGENTS.md",
32584
+ message: "Missing project context line after the title heading",
32585
+ fix: "Add a single-line description: stack + what the project does"
32586
+ });
32587
+ } else if (contextLines.length > 1) {
32588
+ issues.push({
32589
+ severity: "warning",
32590
+ file: "AGENTS.md",
32591
+ message: `Project context should be exactly 1 line, found ${contextLines.length}`,
32592
+ fix: "Condense to a single line: stack + what the project does"
32593
+ });
32594
+ }
32595
+ const codeBlockRe = /```[\s\S]*?```/g;
32596
+ let blockMatch;
32597
+ while ((blockMatch = codeBlockRe.exec(agentsMd)) !== null) {
32598
+ const block = blockMatch[0];
32599
+ const cmdRe = /(?:bun|npm|pnpm|yarn)\s+(?:run\s+)?(\S+)/g;
32600
+ let cmdMatch;
32601
+ while ((cmdMatch = cmdRe.exec(block)) !== null) {
32602
+ const scriptName = cmdMatch[1];
32603
+ const builtins = new Set([
32604
+ "install",
32605
+ "init",
32606
+ "create",
32607
+ "exec",
32608
+ "dlx",
32609
+ "x",
32610
+ "test",
32611
+ "start"
32612
+ ]);
32613
+ if (builtins.has(scriptName))
32614
+ continue;
32615
+ if (Object.keys(pkgScripts).length > 0 && !(scriptName in pkgScripts)) {
32616
+ issues.push({
32617
+ severity: "warning",
32618
+ file: "AGENTS.md",
32619
+ message: `Command references script "${scriptName}" which is not in package.json`,
32620
+ fix: `Update the command or add "${scriptName}" to package.json scripts`
32621
+ });
32622
+ }
32623
+ }
32624
+ }
32625
+ const standardsSection = extractSection(agentsMd, "Code Standards");
32626
+ if (standardsSection) {
32627
+ const lower = standardsSection.toLowerCase();
32628
+ for (const phrase of VAGUE_STANDARDS) {
32629
+ if (lower.includes(phrase)) {
32630
+ issues.push({
32631
+ severity: "warning",
32632
+ file: "AGENTS.md",
32633
+ message: `Code Standards contains vague phrase: "${phrase}"`,
32634
+ fix: "Replace with specific, verifiable conventions derived from config files"
32635
+ });
32636
+ }
32637
+ }
32638
+ }
32639
+ if (Object.keys(pkgScripts).length > 0) {
32640
+ const hasTestScript = Object.keys(pkgScripts).some((k3) => k3 === "test" || k3.startsWith("test:"));
32641
+ if (!hasTestScript) {
32642
+ const mentionsNoTest = agentsMd.toLowerCase().includes("no test");
32643
+ if (!mentionsNoTest) {
32644
+ issues.push({
32645
+ severity: "warning",
32646
+ file: "AGENTS.md",
32647
+ message: "No test script in package.json and AGENTS.md doesn't mention it",
32648
+ fix: 'Add a note like "No test framework. Verify changes with `bun run build`."'
32649
+ });
32650
+ }
32651
+ }
32652
+ }
32653
+ checkBacktickPaths(agentsMd, "AGENTS.md", cwd, issues);
32654
+ }
32655
+ const archMd = readText(join4(cwd, "docs", "architecture.md"));
32656
+ if (archMd) {
32657
+ checkBacktickPaths(archMd, "docs/architecture.md", cwd, issues);
32658
+ }
32659
+ return issues;
32660
+ }
32661
+ function extractHeadings(content) {
32662
+ const headings = new Set;
32663
+ for (const line of content.split(`
32664
+ `)) {
32665
+ const match = line.match(/^#{2,3}\s+(.+)$/);
32666
+ if (match) {
32667
+ headings.add(match[1].trim());
32668
+ }
32669
+ }
32670
+ return headings;
32671
+ }
32672
+ function extractSection(content, heading) {
32673
+ const lines = content.split(`
32674
+ `);
32675
+ let capturing = false;
32676
+ const result = [];
32677
+ for (const line of lines) {
32678
+ if (capturing) {
32679
+ if (line.match(/^#{1,2}\s/))
32680
+ break;
32681
+ result.push(line);
32682
+ } else if (line.match(new RegExp(`^##\\s+${heading.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`, "i"))) {
32683
+ capturing = true;
32684
+ }
32685
+ }
32686
+ return result.length > 0 ? result.join(`
32687
+ `) : null;
32688
+ }
32689
+ function checkBacktickPaths(content, file2, cwd, issues) {
32690
+ const pathRe = /`((?:src\/|packages\/|apps\/|supabase\/|docs\/)[^`]+)`/g;
32691
+ let match;
32692
+ const checked = new Set;
32693
+ const root = resolve(cwd);
32694
+ while ((match = pathRe.exec(content)) !== null) {
32695
+ const refPath = match[1].replace(/\/$/, "");
32696
+ if (checked.has(refPath))
32697
+ continue;
32698
+ checked.add(refPath);
32699
+ const resolvedRef = resolve(root, refPath);
32700
+ if (resolvedRef !== root && !resolvedRef.startsWith(root + sep2))
32701
+ continue;
32702
+ if (!existsSync5(resolvedRef)) {
32703
+ issues.push({
32704
+ severity: "warning",
32705
+ file: file2,
32706
+ message: `Referenced path does not exist: ${refPath}`,
32707
+ fix: `Update or remove the \`${refPath}\` reference`
32708
+ });
32709
+ }
32710
+ }
32711
+ }
32712
+ async function runDocsStep(cwd) {
32713
+ const info = scanProject(cwd);
32714
+ const hasDocs = info.existingDocs.agentsMd || info.existingDocs.claudeMd;
32715
+ if (!hasDocs) {
32716
+ const shouldGenerate = await ye({
32717
+ message: "No project docs found. Generate AGENTS.md and CLAUDE.md?",
32718
+ initialValue: true
32719
+ });
32720
+ if (pD(shouldGenerate) || !shouldGenerate) {
32721
+ return { files: [], issues: [], skipped: true };
32722
+ }
32723
+ const files = [];
32724
+ files.push({
32725
+ path: join4(cwd, "AGENTS.md"),
32726
+ content: generateAgentsMd(info, cwd),
32727
+ type: "text"
32728
+ });
32729
+ files.push({
32730
+ path: join4(cwd, "CLAUDE.md"),
32731
+ content: generateClaudeMd(info),
32732
+ type: "text"
32733
+ });
32734
+ if (info.dirs.includes("docs") || info.srcDirs.length > 0) {
32735
+ files.push({
32736
+ path: join4(cwd, "docs", "architecture.md"),
32737
+ content: generateArchitectureMd(info, cwd),
32738
+ type: "text"
32739
+ });
32740
+ }
32741
+ M2.success(`Generated ${files.length} doc file(s): ${files.map((f) => f.path.replace(cwd + "/", "")).join(", ")}`);
32742
+ return { files, issues: [], skipped: false };
32743
+ }
32744
+ const shouldVerify = await ye({
32745
+ message: "Project docs found. Verify for issues?",
32746
+ initialValue: false
32747
+ });
32748
+ if (pD(shouldVerify) || !shouldVerify) {
32749
+ return { files: [], issues: [], skipped: true };
32750
+ }
32751
+ const issues = verifyDocs(cwd);
32752
+ if (issues.length === 0) {
32753
+ M2.success("No issues found in project docs.");
32754
+ } else {
32755
+ for (const issue2 of issues) {
32756
+ const prefix = `${colors.bold(issue2.file)}:`;
32757
+ if (issue2.severity === "error") {
32758
+ M2.error(`${prefix} ${issue2.message}`);
32759
+ } else {
32760
+ M2.warning(`${prefix} ${issue2.message}`);
32761
+ }
32762
+ if (issue2.fix) {
32763
+ M2.message(` ${symbols.arrow} ${colors.dim(issue2.fix)}`);
32764
+ }
32765
+ }
32766
+ M2.info(`Found ${issues.length} issue(s) (${issues.filter((i) => i.severity === "error").length} errors, ${issues.filter((i) => i.severity === "warning").length} warnings)`);
32767
+ }
32768
+ return { files: [], issues, skipped: false };
32769
+ }
32511
32770
 
32512
- Report the result:
32513
- - "Created N cards in 'To Do'. Use \`/hmy #<id>\` to start working on any card."
32514
- - List the created cards with their short IDs
32771
+ // src/tui/writer.ts
32772
+ import { existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "node:fs";
32773
+ import { homedir as homedir3 } from "node:os";
32774
+ import { dirname as dirname2 } from "node:path";
32775
+ function ensureDir(dirPath) {
32776
+ if (!existsSync6(dirPath)) {
32777
+ mkdirSync4(dirPath, { recursive: true, mode: 493 });
32778
+ }
32779
+ }
32780
+ function writeFile(filePath, content, options = {}) {
32781
+ const exists = existsSync6(filePath);
32782
+ if (exists && !options.force) {
32783
+ return { path: filePath, action: "skip" };
32784
+ }
32785
+ try {
32786
+ ensureDir(dirname2(filePath));
32787
+ const mode = filePath.includes(".harmony-mcp") ? 384 : 420;
32788
+ writeFileSync4(filePath, content, { mode });
32789
+ return { path: filePath, action: exists ? "update" : "create" };
32790
+ } catch (error48) {
32791
+ return {
32792
+ path: filePath,
32793
+ action: "skip",
32794
+ error: error48 instanceof Error ? error48.message : String(error48)
32795
+ };
32796
+ }
32797
+ }
32798
+ function mergeJsonFile(filePath, updates, options = {}) {
32799
+ const exists = existsSync6(filePath);
32800
+ if (!exists) {
32801
+ try {
32802
+ ensureDir(dirname2(filePath));
32803
+ writeFileSync4(filePath, JSON.stringify(updates, null, 2), {
32804
+ mode: 420
32805
+ });
32806
+ return { path: filePath, action: "create" };
32807
+ } catch (error48) {
32808
+ return {
32809
+ path: filePath,
32810
+ action: "skip",
32811
+ error: error48 instanceof Error ? error48.message : String(error48)
32812
+ };
32813
+ }
32814
+ }
32815
+ try {
32816
+ const existing = JSON.parse(readFileSync5(filePath, "utf-8"));
32817
+ if (updates.mcpServers && existing.mcpServers) {
32818
+ const existingServers = existing.mcpServers;
32819
+ const updateServers = updates.mcpServers;
32820
+ existing.mcpServers = { ...existingServers, ...updateServers };
32821
+ } else {
32822
+ Object.assign(existing, updates);
32823
+ }
32824
+ writeFileSync4(filePath, JSON.stringify(existing, null, 2), { mode: 420 });
32825
+ return { path: filePath, action: "merge" };
32826
+ } catch {
32827
+ if (options.force) {
32828
+ try {
32829
+ writeFileSync4(filePath, JSON.stringify(updates, null, 2), {
32830
+ mode: 420
32831
+ });
32832
+ return { path: filePath, action: "update" };
32833
+ } catch (error48) {
32834
+ return {
32835
+ path: filePath,
32836
+ action: "skip",
32837
+ error: error48 instanceof Error ? error48.message : String(error48)
32838
+ };
32839
+ }
32840
+ }
32841
+ return {
32842
+ path: filePath,
32843
+ action: "skip",
32844
+ error: "Could not parse existing file"
32845
+ };
32846
+ }
32847
+ }
32848
+ function appendToToml(filePath, section, content, options = {}) {
32849
+ const exists = existsSync6(filePath);
32850
+ if (!exists) {
32851
+ try {
32852
+ ensureDir(dirname2(filePath));
32853
+ writeFileSync4(filePath, content, { mode: 420 });
32854
+ return { path: filePath, action: "create" };
32855
+ } catch (error48) {
32856
+ return {
32857
+ path: filePath,
32858
+ action: "skip",
32859
+ error: error48 instanceof Error ? error48.message : String(error48)
32860
+ };
32861
+ }
32862
+ }
32863
+ try {
32864
+ const existing = readFileSync5(filePath, "utf-8");
32865
+ if (existing.includes(section)) {
32866
+ if (options.force) {
32867
+ const updated = existing.replace(new RegExp(`\\[${section.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\][\\s\\S]*?(?=\\[|$)`), content.trim() + `
32515
32868
 
32516
- ## Key Tools Reference
32869
+ `);
32870
+ writeFileSync4(filePath, updated, { mode: 420 });
32871
+ return { path: filePath, action: "update" };
32872
+ }
32873
+ return { path: filePath, action: "skip" };
32874
+ }
32875
+ writeFileSync4(filePath, existing + `
32876
+ ` + content, { mode: 420 });
32877
+ return { path: filePath, action: "merge" };
32878
+ } catch (error48) {
32879
+ return {
32880
+ path: filePath,
32881
+ action: "skip",
32882
+ error: error48 instanceof Error ? error48.message : String(error48)
32883
+ };
32884
+ }
32885
+ }
32886
+ async function writeFilesWithProgress(files, options = {}) {
32887
+ const results = [];
32888
+ const home = homedir3();
32889
+ const spinner = Y2();
32890
+ spinner.start("Writing configuration files...");
32891
+ for (const file2 of files) {
32892
+ let result;
32893
+ if (file2.type === "json") {
32894
+ const jsonContent = JSON.parse(file2.content);
32895
+ result = mergeJsonFile(file2.path, jsonContent, options);
32896
+ } else if (file2.type === "toml" && file2.tomlSection) {
32897
+ result = appendToToml(file2.path, file2.tomlSection, file2.content, options);
32898
+ } else {
32899
+ result = writeFile(file2.path, file2.content, options);
32900
+ }
32901
+ results.push(result);
32902
+ await new Promise((resolve2) => setTimeout(resolve2, 50));
32903
+ }
32904
+ spinner.stop("Files written");
32905
+ for (const result of results) {
32906
+ const displayPath = formatPath(result.path, home);
32907
+ if (result.error) {
32908
+ console.log(messages.fileError(displayPath, result.error));
32909
+ } else if (result.action === "skip") {
32910
+ console.log(messages.fileSkipped(displayPath));
32911
+ } else {
32912
+ const actionLabel = result.action === "merge" ? "updated" : "created";
32913
+ console.log(` ${colors.success("✓")} ${colors.dim(displayPath)} ${colors.dim(`(${actionLabel})`)}`);
32914
+ }
32915
+ }
32916
+ return results;
32917
+ }
32918
+ function getWriteSummary(files, options = {}) {
32919
+ const toCreate = [];
32920
+ const toUpdate = [];
32921
+ const toSkip = [];
32922
+ const home = homedir3();
32923
+ for (const file2 of files) {
32924
+ const displayPath = formatPath(file2.path, home);
32925
+ const exists = existsSync6(file2.path);
32926
+ if (exists && !options.force) {
32927
+ toSkip.push(displayPath);
32928
+ } else if (exists) {
32929
+ toUpdate.push(displayPath);
32930
+ } else {
32931
+ toCreate.push(displayPath);
32932
+ }
32933
+ }
32934
+ return { toCreate, toUpdate, toSkip };
32935
+ }
32517
32936
 
32518
- **Discovery:** \`harmony_list_plans\`, \`harmony_get_plan\`, \`harmony_get_card_by_short_id\`
32519
- **Context:** \`harmony_get_board\`, \`harmony_recall\`, \`harmony_memory_search\`
32520
- **Planning:** \`harmony_create_plan\`, \`harmony_advance_plan\`, \`harmony_update_plan\`
32521
- **Execution:** \`harmony_create_card\`, \`harmony_update_card\`
32522
- `;
32937
+ // src/tui/setup.ts
32938
+ var GLOBAL_SKILLS_DIR = join5(homedir4(), ".agents", "skills");
32939
+ var API_URL = "https://gethmy.com/api";
32523
32940
  async function registerMcpServer() {
32524
32941
  try {
32525
32942
  const { execSync } = await import("node:child_process");
@@ -32532,16 +32949,16 @@ async function registerMcpServer() {
32532
32949
  }
32533
32950
  }
32534
32951
  async function writeMcpConfigFallback(home) {
32535
- const { readFileSync: readFileSync5, writeFileSync: writeFileSync4, mkdirSync: mkdirSync5, existsSync: existsSync7 } = await import("node:fs");
32952
+ const { readFileSync: readFileSync6, writeFileSync: writeFileSync5, mkdirSync: mkdirSync6, existsSync: existsSync8 } = await import("node:fs");
32536
32953
  const settingsPath = join5(home, ".claude", "settings.json");
32537
- const settingsDir = dirname2(settingsPath);
32538
- if (!existsSync7(settingsDir)) {
32539
- mkdirSync5(settingsDir, { recursive: true });
32954
+ const settingsDir = dirname3(settingsPath);
32955
+ if (!existsSync8(settingsDir)) {
32956
+ mkdirSync6(settingsDir, { recursive: true });
32540
32957
  }
32541
32958
  let settings = {};
32542
- if (existsSync7(settingsPath)) {
32959
+ if (existsSync8(settingsPath)) {
32543
32960
  try {
32544
- settings = JSON.parse(readFileSync5(settingsPath, "utf-8"));
32961
+ settings = JSON.parse(readFileSync6(settingsPath, "utf-8"));
32545
32962
  } catch {}
32546
32963
  }
32547
32964
  const mcpServers = settings.mcpServers || {};
@@ -32550,7 +32967,7 @@ async function writeMcpConfigFallback(home) {
32550
32967
  args: ["-y", "@gethmy/mcp@latest", "serve"]
32551
32968
  };
32552
32969
  settings.mcpServers = mcpServers;
32553
- writeFileSync4(settingsPath, JSON.stringify(settings, null, 2));
32970
+ writeFileSync5(settingsPath, JSON.stringify(settings, null, 2));
32554
32971
  }
32555
32972
  async function validateApiKey(apiKey, apiUrl = API_URL) {
32556
32973
  try {
@@ -32621,22 +33038,8 @@ function getAgentFiles(agentId, cwd, installMode = "global") {
32621
33038
  const symlinks = [];
32622
33039
  switch (agentId) {
32623
33040
  case "claude": {
32624
- const skillContent = `---
32625
- name: hmy
32626
- description: Start working on a Harmony card. Use when given a card reference like #42, UUID, or card name to implement.
32627
- argument-hint: <card-reference>
32628
- ---
32629
-
32630
- ${HARMONY_WORKFLOW_PROMPT.replace("Your agent identifier", "claude-code").replace("Your agent name", "Claude Code")}
32631
- `;
32632
- const planSkillContent = `---
32633
- name: hmy-plan
32634
- description: Create a new plan or work on an existing one. Use when asked to plan a feature, execute a plan, review a plan, or given a plan reference.
32635
- argument-hint: [plan name, ID, or topic to plan]
32636
- ---
32637
-
32638
- ${HARMONY_PLAN_PROMPT.replace("$ARGUMENTS", "$ARGUMENTS")}
32639
- `;
33041
+ const skillContent = buildSkillFile("hmy", "claude");
33042
+ const planSkillContent = buildSkillFile("hmy-plan", "claude");
32640
33043
  if (installMode === "global") {
32641
33044
  files.push({
32642
33045
  path: join5(GLOBAL_SKILLS_DIR, "hmy", "SKILL.md"),
@@ -33110,9 +33513,9 @@ async function runSetup(options = {}) {
33110
33513
  if (allSymlinks.length > 0) {
33111
33514
  for (const symlink of allSymlinks) {
33112
33515
  try {
33113
- const linkDir = dirname2(symlink.link);
33114
- if (!existsSync6(linkDir)) {
33115
- mkdirSync4(linkDir, { recursive: true });
33516
+ const linkDir = dirname3(symlink.link);
33517
+ if (!existsSync7(linkDir)) {
33518
+ mkdirSync5(linkDir, { recursive: true });
33116
33519
  }
33117
33520
  let linkExists = false;
33118
33521
  try {
@@ -33188,6 +33591,7 @@ var require2 = createRequire2(import.meta.url);
33188
33591
  var { version: version2 } = require2("../package.json");
33189
33592
  program.name("@gethmy/mcp").description("MCP server for Harmony Kanban board").version(version2);
33190
33593
  program.command("serve").description("Start the MCP server (stdio transport)").action(async () => {
33594
+ await refreshSkills();
33191
33595
  const server = new HarmonyMCPServer;
33192
33596
  await server.run();
33193
33597
  });