oathbound 0.15.1 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.cjs +675 -175
  2. package/package.json +1 -1
package/dist/cli.cjs CHANGED
@@ -11518,12 +11518,12 @@ var require_resolve_flow_scalar = __commonJS((exports2) => {
11518
11518
  };
11519
11519
  }
11520
11520
  const valueEnd = offset + source.length;
11521
- const re = resolveEnd.resolveEnd(end, valueEnd, strict, onError);
11521
+ const re2 = resolveEnd.resolveEnd(end, valueEnd, strict, onError);
11522
11522
  return {
11523
11523
  value,
11524
11524
  type: _type,
11525
- comment: re.comment,
11526
- range: [offset, valueEnd, re.offset]
11525
+ comment: re2.comment,
11526
+ range: [offset, valueEnd, re2.offset]
11527
11527
  };
11528
11528
  }
11529
11529
  function plainValue(source, onError) {
@@ -11895,10 +11895,10 @@ var require_compose_node = __commonJS((exports2) => {
11895
11895
  if (alias.source.endsWith(":"))
11896
11896
  onError(offset + source.length - 1, "BAD_ALIAS", "Alias ending in : is ambiguous", true);
11897
11897
  const valueEnd = offset + source.length;
11898
- const re = resolveEnd.resolveEnd(end, valueEnd, options.strict, onError);
11899
- alias.range = [offset, valueEnd, re.offset];
11900
- if (re.comment)
11901
- alias.comment = re.comment;
11898
+ const re2 = resolveEnd.resolveEnd(end, valueEnd, options.strict, onError);
11899
+ alias.range = [offset, valueEnd, re2.offset];
11900
+ if (re2.comment)
11901
+ alias.comment = re2.comment;
11902
11902
  return alias;
11903
11903
  }
11904
11904
  exports2.composeEmptyNode = composeEmptyNode;
@@ -11936,10 +11936,10 @@ var require_compose_doc = __commonJS((exports2) => {
11936
11936
  }
11937
11937
  doc.contents = value ? composeNode.composeNode(ctx, value, props, onError) : composeNode.composeEmptyNode(ctx, props.end, start, null, props, onError);
11938
11938
  const contentEnd = doc.contents.range[2];
11939
- const re = resolveEnd.resolveEnd(end, contentEnd, false, onError);
11940
- if (re.comment)
11941
- doc.comment = re.comment;
11942
- doc.range = [offset, contentEnd, re.offset];
11939
+ const re2 = resolveEnd.resolveEnd(end, contentEnd, false, onError);
11940
+ if (re2.comment)
11941
+ doc.comment = re2.comment;
11942
+ doc.range = [offset, contentEnd, re2.offset];
11943
11943
  return doc;
11944
11944
  }
11945
11945
  exports2.composeDoc = composeDoc;
@@ -14157,6 +14157,7 @@ __export(exports_cli, {
14157
14157
  mergeClaudeSettings: () => mergeClaudeSettings,
14158
14158
  isNewer: () => isNewer,
14159
14159
  installDevDependency: () => installDevDependency,
14160
+ findSkillsDirs: () => findSkillsDirs,
14160
14161
  addPrepareScript: () => addPrepareScript
14161
14162
  });
14162
14163
  module.exports = __toCommonJS(exports_cli);
@@ -16478,9 +16479,9 @@ if (shouldShowDeprecationWarning())
16478
16479
 
16479
16480
  // cli.ts
16480
16481
  var import_node_crypto2 = require("node:crypto");
16481
- var import_node_child_process2 = require("node:child_process");
16482
- var import_node_fs8 = require("node:fs");
16483
- var import_node_path8 = require("node:path");
16482
+ var import_node_child_process3 = require("node:child_process");
16483
+ var import_node_fs9 = require("node:fs");
16484
+ var import_node_path9 = require("node:path");
16484
16485
  var import_node_os4 = require("node:os");
16485
16486
 
16486
16487
  // node_modules/@clack/core/dist/index.mjs
@@ -16703,7 +16704,15 @@ function W(t, e) {
16703
16704
  const s = t;
16704
16705
  s.isTTY && s.setRawMode(e);
16705
16706
  }
16707
+ var rt = (t) => ("columns" in t) && typeof t.columns == "number" ? t.columns : 80;
16706
16708
  var nt = (t) => ("rows" in t) && typeof t.rows == "number" ? t.rows : 20;
16709
+ function Bt(t, e, s, i = s) {
16710
+ const r = rt(t ?? import_node_process.stdout);
16711
+ return K(e, r - s.length, { hard: true, trim: false }).split(`
16712
+ `).map((n, u) => `${u === 0 ? i : s}${n}`).join(`
16713
+ `);
16714
+ }
16715
+
16707
16716
  class B {
16708
16717
  input;
16709
16718
  output;
@@ -16972,6 +16981,33 @@ class yt extends B {
16972
16981
  });
16973
16982
  }
16974
16983
  }
16984
+ class Tt extends B {
16985
+ options;
16986
+ cursor = 0;
16987
+ get _selectedValue() {
16988
+ return this.options[this.cursor];
16989
+ }
16990
+ changeValue() {
16991
+ this.value = this._selectedValue.value;
16992
+ }
16993
+ constructor(e) {
16994
+ super(e, false), this.options = e.options;
16995
+ const s = this.options.findIndex(({ value: r }) => r === e.initialValue), i = s === -1 ? 0 : s;
16996
+ this.cursor = this.options[i].disabled ? x(i, 1, this.options) : i, this.changeValue(), this.on("cursor", (r) => {
16997
+ switch (r) {
16998
+ case "left":
16999
+ case "up":
17000
+ this.cursor = x(this.cursor, -1, this.options);
17001
+ break;
17002
+ case "down":
17003
+ case "right":
17004
+ this.cursor = x(this.cursor, 1, this.options);
17005
+ break;
17006
+ }
17007
+ this.changeValue();
17008
+ });
17009
+ }
17010
+ }
16975
17011
 
16976
17012
  // node_modules/@clack/prompts/dist/index.mjs
16977
17013
  var import_node_util2 = require("node:util");
@@ -17020,13 +17056,234 @@ var W2 = (e) => {
17020
17056
  return import_node_util2.styleText("green", V);
17021
17057
  }
17022
17058
  };
17059
+ var ve = (e) => {
17060
+ switch (e) {
17061
+ case "initial":
17062
+ case "active":
17063
+ return import_node_util2.styleText("cyan", h);
17064
+ case "cancel":
17065
+ return import_node_util2.styleText("red", h);
17066
+ case "error":
17067
+ return import_node_util2.styleText("yellow", h);
17068
+ case "submit":
17069
+ return import_node_util2.styleText("green", h);
17070
+ }
17071
+ };
17072
+ var mt2 = (e) => e === 161 || e === 164 || e === 167 || e === 168 || e === 170 || e === 173 || e === 174 || e >= 176 && e <= 180 || e >= 182 && e <= 186 || e >= 188 && e <= 191 || e === 198 || e === 208 || e === 215 || e === 216 || e >= 222 && e <= 225 || e === 230 || e >= 232 && e <= 234 || e === 236 || e === 237 || e === 240 || e === 242 || e === 243 || e >= 247 && e <= 250 || e === 252 || e === 254 || e === 257 || e === 273 || e === 275 || e === 283 || e === 294 || e === 295 || e === 299 || e >= 305 && e <= 307 || e === 312 || e >= 319 && e <= 322 || e === 324 || e >= 328 && e <= 331 || e === 333 || e === 338 || e === 339 || e === 358 || e === 359 || e === 363 || e === 462 || e === 464 || e === 466 || e === 468 || e === 470 || e === 472 || e === 474 || e === 476 || e === 593 || e === 609 || e === 708 || e === 711 || e >= 713 && e <= 715 || e === 717 || e === 720 || e >= 728 && e <= 731 || e === 733 || e === 735 || e >= 768 && e <= 879 || e >= 913 && e <= 929 || e >= 931 && e <= 937 || e >= 945 && e <= 961 || e >= 963 && e <= 969 || e === 1025 || e >= 1040 && e <= 1103 || e === 1105 || e === 8208 || e >= 8211 && e <= 8214 || e === 8216 || e === 8217 || e === 8220 || e === 8221 || e >= 8224 && e <= 8226 || e >= 8228 && e <= 8231 || e === 8240 || e === 8242 || e === 8243 || e === 8245 || e === 8251 || e === 8254 || e === 8308 || e === 8319 || e >= 8321 && e <= 8324 || e === 8364 || e === 8451 || e === 8453 || e === 8457 || e === 8467 || e === 8470 || e === 8481 || e === 8482 || e === 8486 || e === 8491 || e === 8531 || e === 8532 || e >= 8539 && e <= 8542 || e >= 8544 && e <= 8555 || e >= 8560 && e <= 8569 || e === 8585 || e >= 8592 && e <= 8601 || e === 8632 || e === 8633 || e === 8658 || e === 8660 || e === 8679 || e === 8704 || e === 8706 || e === 8707 || e === 8711 || e === 8712 || e === 8715 || e === 8719 || e === 8721 || e === 8725 || e === 8730 || e >= 8733 && e <= 8736 || e === 8739 || e === 8741 || e >= 8743 && e <= 8748 || e === 8750 || e >= 8756 && e <= 8759 || e === 8764 || e === 8765 || e === 8776 || e === 8780 || e === 8786 || e === 8800 || e === 8801 || e >= 8804 && e <= 8807 || e === 8810 || e === 8811 || e === 8814 || e === 8815 || e === 8834 || e === 8835 || e === 8838 || e === 8839 || e === 8853 || e === 8857 || e === 8869 || e === 8895 || e === 8978 || e >= 9312 && e <= 9449 || e >= 9451 && e <= 9547 || e >= 9552 && e <= 9587 || e >= 9600 && e <= 9615 || e >= 9618 && e <= 9621 || e === 9632 || e === 9633 || e >= 9635 && e <= 9641 || e === 9650 || e === 9651 || e === 9654 || e === 9655 || e === 9660 || e === 9661 || e === 9664 || e === 9665 || e >= 9670 && e <= 9672 || e === 9675 || e >= 9678 && e <= 9681 || e >= 9698 && e <= 9701 || e === 9711 || e === 9733 || e === 9734 || e === 9737 || e === 9742 || e === 9743 || e === 9756 || e === 9758 || e === 9792 || e === 9794 || e === 9824 || e === 9825 || e >= 9827 && e <= 9829 || e >= 9831 && e <= 9834 || e === 9836 || e === 9837 || e === 9839 || e === 9886 || e === 9887 || e === 9919 || e >= 9926 && e <= 9933 || e >= 9935 && e <= 9939 || e >= 9941 && e <= 9953 || e === 9955 || e === 9960 || e === 9961 || e >= 9963 && e <= 9969 || e === 9972 || e >= 9974 && e <= 9977 || e === 9979 || e === 9980 || e === 9982 || e === 9983 || e === 10045 || e >= 10102 && e <= 10111 || e >= 11094 && e <= 11097 || e >= 12872 && e <= 12879 || e >= 57344 && e <= 63743 || e >= 65024 && e <= 65039 || e === 65533 || e >= 127232 && e <= 127242 || e >= 127248 && e <= 127277 || e >= 127280 && e <= 127337 || e >= 127344 && e <= 127373 || e === 127375 || e === 127376 || e >= 127387 && e <= 127404 || e >= 917760 && e <= 917999 || e >= 983040 && e <= 1048573 || e >= 1048576 && e <= 1114109;
17073
+ var gt2 = (e) => e === 12288 || e >= 65281 && e <= 65376 || e >= 65504 && e <= 65510;
17074
+ var ft2 = (e) => e >= 4352 && e <= 4447 || e === 8986 || e === 8987 || e === 9001 || e === 9002 || e >= 9193 && e <= 9196 || e === 9200 || e === 9203 || e === 9725 || e === 9726 || e === 9748 || e === 9749 || e >= 9800 && e <= 9811 || e === 9855 || e === 9875 || e === 9889 || e === 9898 || e === 9899 || e === 9917 || e === 9918 || e === 9924 || e === 9925 || e === 9934 || e === 9940 || e === 9962 || e === 9970 || e === 9971 || e === 9973 || e === 9978 || e === 9981 || e === 9989 || e === 9994 || e === 9995 || e === 10024 || e === 10060 || e === 10062 || e >= 10067 && e <= 10069 || e === 10071 || e >= 10133 && e <= 10135 || e === 10160 || e === 10175 || e === 11035 || e === 11036 || e === 11088 || e === 11093 || e >= 11904 && e <= 11929 || e >= 11931 && e <= 12019 || e >= 12032 && e <= 12245 || e >= 12272 && e <= 12287 || e >= 12289 && e <= 12350 || e >= 12353 && e <= 12438 || e >= 12441 && e <= 12543 || e >= 12549 && e <= 12591 || e >= 12593 && e <= 12686 || e >= 12688 && e <= 12771 || e >= 12783 && e <= 12830 || e >= 12832 && e <= 12871 || e >= 12880 && e <= 19903 || e >= 19968 && e <= 42124 || e >= 42128 && e <= 42182 || e >= 43360 && e <= 43388 || e >= 44032 && e <= 55203 || e >= 63744 && e <= 64255 || e >= 65040 && e <= 65049 || e >= 65072 && e <= 65106 || e >= 65108 && e <= 65126 || e >= 65128 && e <= 65131 || e >= 94176 && e <= 94180 || e === 94192 || e === 94193 || e >= 94208 && e <= 100343 || e >= 100352 && e <= 101589 || e >= 101632 && e <= 101640 || e >= 110576 && e <= 110579 || e >= 110581 && e <= 110587 || e === 110589 || e === 110590 || e >= 110592 && e <= 110882 || e === 110898 || e >= 110928 && e <= 110930 || e === 110933 || e >= 110948 && e <= 110951 || e >= 110960 && e <= 111355 || e === 126980 || e === 127183 || e === 127374 || e >= 127377 && e <= 127386 || e >= 127488 && e <= 127490 || e >= 127504 && e <= 127547 || e >= 127552 && e <= 127560 || e === 127568 || e === 127569 || e >= 127584 && e <= 127589 || e >= 127744 && e <= 127776 || e >= 127789 && e <= 127797 || e >= 127799 && e <= 127868 || e >= 127870 && e <= 127891 || e >= 127904 && e <= 127946 || e >= 127951 && e <= 127955 || e >= 127968 && e <= 127984 || e === 127988 || e >= 127992 && e <= 128062 || e === 128064 || e >= 128066 && e <= 128252 || e >= 128255 && e <= 128317 || e >= 128331 && e <= 128334 || e >= 128336 && e <= 128359 || e === 128378 || e === 128405 || e === 128406 || e === 128420 || e >= 128507 && e <= 128591 || e >= 128640 && e <= 128709 || e === 128716 || e >= 128720 && e <= 128722 || e >= 128725 && e <= 128727 || e >= 128732 && e <= 128735 || e === 128747 || e === 128748 || e >= 128756 && e <= 128764 || e >= 128992 && e <= 129003 || e === 129008 || e >= 129292 && e <= 129338 || e >= 129340 && e <= 129349 || e >= 129351 && e <= 129535 || e >= 129648 && e <= 129660 || e >= 129664 && e <= 129672 || e >= 129680 && e <= 129725 || e >= 129727 && e <= 129733 || e >= 129742 && e <= 129755 || e >= 129760 && e <= 129768 || e >= 129776 && e <= 129784 || e >= 131072 && e <= 196605 || e >= 196608 && e <= 262141;
17075
+ var we = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/y;
17076
+ var re = /[\x00-\x08\x0A-\x1F\x7F-\x9F]{1,1000}/y;
17077
+ var ie = /\t{1,1000}/y;
17078
+ var Ae = /[\u{1F1E6}-\u{1F1FF}]{2}|\u{1F3F4}[\u{E0061}-\u{E007A}]{2}[\u{E0030}-\u{E0039}\u{E0061}-\u{E007A}]{1,3}\u{E007F}|(?:\p{Emoji}\uFE0F\u20E3?|\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation})(?:\u200D(?:\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation}|\p{Emoji}\uFE0F\u20E3?))*/yu;
17079
+ var ne = /(?:[\x20-\x7E\xA0-\xFF](?!\uFE0F)){1,1000}/y;
17080
+ var Ft2 = /\p{M}+/gu;
17023
17081
  var yt2 = { limit: 1 / 0, ellipsis: "" };
17082
+ var Le = (e, r = {}, s = {}) => {
17083
+ const i = r.limit ?? 1 / 0, a = r.ellipsis ?? "", o = r?.ellipsisWidth ?? (a ? Le(a, yt2, s).width : 0), u = s.ansiWidth ?? 0, l = s.controlWidth ?? 0, n = s.tabWidth ?? 8, c = s.ambiguousWidth ?? 1, p = s.emojiWidth ?? 2, f = s.fullWidthWidth ?? 2, g = s.regularWidth ?? 1, E = s.wideWidth ?? 2;
17084
+ let $ = 0, m = 0, d = e.length, F = 0, y2 = false, v = d, C = Math.max(0, i - o), A = 0, b = 0, w = 0, S2 = 0;
17085
+ e:
17086
+ for (;; ) {
17087
+ if (b > A || m >= d && m > $) {
17088
+ const T2 = e.slice(A, b) || e.slice($, m);
17089
+ F = 0;
17090
+ for (const M2 of T2.replaceAll(Ft2, "")) {
17091
+ const O2 = M2.codePointAt(0) || 0;
17092
+ if (gt2(O2) ? S2 = f : ft2(O2) ? S2 = E : c !== g && mt2(O2) ? S2 = c : S2 = g, w + S2 > C && (v = Math.min(v, Math.max(A, $) + F)), w + S2 > i) {
17093
+ y2 = true;
17094
+ break e;
17095
+ }
17096
+ F += M2.length, w += S2;
17097
+ }
17098
+ A = b = 0;
17099
+ }
17100
+ if (m >= d)
17101
+ break;
17102
+ if (ne.lastIndex = m, ne.test(e)) {
17103
+ if (F = ne.lastIndex - m, S2 = F * g, w + S2 > C && (v = Math.min(v, m + Math.floor((C - w) / g))), w + S2 > i) {
17104
+ y2 = true;
17105
+ break;
17106
+ }
17107
+ w += S2, A = $, b = m, m = $ = ne.lastIndex;
17108
+ continue;
17109
+ }
17110
+ if (we.lastIndex = m, we.test(e)) {
17111
+ if (w + u > C && (v = Math.min(v, m)), w + u > i) {
17112
+ y2 = true;
17113
+ break;
17114
+ }
17115
+ w += u, A = $, b = m, m = $ = we.lastIndex;
17116
+ continue;
17117
+ }
17118
+ if (re.lastIndex = m, re.test(e)) {
17119
+ if (F = re.lastIndex - m, S2 = F * l, w + S2 > C && (v = Math.min(v, m + Math.floor((C - w) / l))), w + S2 > i) {
17120
+ y2 = true;
17121
+ break;
17122
+ }
17123
+ w += S2, A = $, b = m, m = $ = re.lastIndex;
17124
+ continue;
17125
+ }
17126
+ if (ie.lastIndex = m, ie.test(e)) {
17127
+ if (F = ie.lastIndex - m, S2 = F * n, w + S2 > C && (v = Math.min(v, m + Math.floor((C - w) / n))), w + S2 > i) {
17128
+ y2 = true;
17129
+ break;
17130
+ }
17131
+ w += S2, A = $, b = m, m = $ = ie.lastIndex;
17132
+ continue;
17133
+ }
17134
+ if (Ae.lastIndex = m, Ae.test(e)) {
17135
+ if (w + p > C && (v = Math.min(v, m)), w + p > i) {
17136
+ y2 = true;
17137
+ break;
17138
+ }
17139
+ w += p, A = $, b = m, m = $ = Ae.lastIndex;
17140
+ continue;
17141
+ }
17142
+ m += 1;
17143
+ }
17144
+ return { width: y2 ? C : w, index: y2 ? v : d, truncated: y2, ellipsed: y2 && i >= o };
17145
+ };
17024
17146
  var Et2 = { limit: 1 / 0, ellipsis: "", ellipsisWidth: 0 };
17147
+ var D2 = (e, r = {}) => Le(e, Et2, r).width;
17148
+ var ae = "\x1B";
17149
+ var je = "›";
17150
+ var vt2 = 39;
17025
17151
  var Ce = "\x07";
17026
17152
  var ke = "[";
17027
17153
  var wt2 = "]";
17154
+ var Ve = "m";
17028
17155
  var Se = `${wt2}8;;`;
17029
17156
  var He = new RegExp(`(?:\\${ke}(?<code>\\d+)m|\\${Se}(?<uri>.*)${Ce})`, "y");
17157
+ var At2 = (e) => {
17158
+ if (e >= 30 && e <= 37 || e >= 90 && e <= 97)
17159
+ return 39;
17160
+ if (e >= 40 && e <= 47 || e >= 100 && e <= 107)
17161
+ return 49;
17162
+ if (e === 1 || e === 2)
17163
+ return 22;
17164
+ if (e === 3)
17165
+ return 23;
17166
+ if (e === 4)
17167
+ return 24;
17168
+ if (e === 7)
17169
+ return 27;
17170
+ if (e === 8)
17171
+ return 28;
17172
+ if (e === 9)
17173
+ return 29;
17174
+ if (e === 0)
17175
+ return 0;
17176
+ };
17177
+ var Ue = (e) => `${ae}${ke}${e}${Ve}`;
17178
+ var Ke = (e) => `${ae}${Se}${e}${Ce}`;
17179
+ var Ct2 = (e) => e.map((r) => D2(r));
17180
+ var Ie = (e, r, s) => {
17181
+ const i = r[Symbol.iterator]();
17182
+ let a = false, o = false, u = e.at(-1), l = u === undefined ? 0 : D2(u), n = i.next(), c = i.next(), p = 0;
17183
+ for (;!n.done; ) {
17184
+ const f = n.value, g = D2(f);
17185
+ l + g <= s ? e[e.length - 1] += f : (e.push(f), l = 0), (f === ae || f === je) && (a = true, o = r.startsWith(Se, p + 1)), a ? o ? f === Ce && (a = false, o = false) : f === Ve && (a = false) : (l += g, l === s && !c.done && (e.push(""), l = 0)), n = c, c = i.next(), p += f.length;
17186
+ }
17187
+ u = e.at(-1), !l && u !== undefined && u.length > 0 && e.length > 1 && (e[e.length - 2] += e.pop());
17188
+ };
17189
+ var St2 = (e) => {
17190
+ const r = e.split(" ");
17191
+ let s = r.length;
17192
+ for (;s > 0 && !(D2(r[s - 1]) > 0); )
17193
+ s--;
17194
+ return s === r.length ? e : r.slice(0, s).join(" ") + r.slice(s).join("");
17195
+ };
17196
+ var It2 = (e, r, s = {}) => {
17197
+ if (s.trim !== false && e.trim() === "")
17198
+ return "";
17199
+ let i = "", a, o;
17200
+ const u = e.split(" "), l = Ct2(u);
17201
+ let n = [""];
17202
+ for (const [$, m] of u.entries()) {
17203
+ s.trim !== false && (n[n.length - 1] = (n.at(-1) ?? "").trimStart());
17204
+ let d = D2(n.at(-1) ?? "");
17205
+ if ($ !== 0 && (d >= r && (s.wordWrap === false || s.trim === false) && (n.push(""), d = 0), (d > 0 || s.trim === false) && (n[n.length - 1] += " ", d++)), s.hard && l[$] > r) {
17206
+ const F = r - d, y2 = 1 + Math.floor((l[$] - F - 1) / r);
17207
+ Math.floor((l[$] - 1) / r) < y2 && n.push(""), Ie(n, m, r);
17208
+ continue;
17209
+ }
17210
+ if (d + l[$] > r && d > 0 && l[$] > 0) {
17211
+ if (s.wordWrap === false && d < r) {
17212
+ Ie(n, m, r);
17213
+ continue;
17214
+ }
17215
+ n.push("");
17216
+ }
17217
+ if (d + l[$] > r && s.wordWrap === false) {
17218
+ Ie(n, m, r);
17219
+ continue;
17220
+ }
17221
+ n[n.length - 1] += m;
17222
+ }
17223
+ s.trim !== false && (n = n.map(($) => St2($)));
17224
+ const c = n.join(`
17225
+ `), p = c[Symbol.iterator]();
17226
+ let f = p.next(), g = p.next(), E = 0;
17227
+ for (;!f.done; ) {
17228
+ const $ = f.value, m = g.value;
17229
+ if (i += $, $ === ae || $ === je) {
17230
+ He.lastIndex = E + 1;
17231
+ const y2 = He.exec(c)?.groups;
17232
+ if (y2?.code !== undefined) {
17233
+ const v = Number.parseFloat(y2.code);
17234
+ a = v === vt2 ? undefined : v;
17235
+ } else
17236
+ y2?.uri !== undefined && (o = y2.uri.length === 0 ? undefined : y2.uri);
17237
+ }
17238
+ const d = a ? At2(a) : undefined;
17239
+ m === `
17240
+ ` ? (o && (i += Ke("")), a && d && (i += Ue(d))) : $ === `
17241
+ ` && (a && d && (i += Ue(a)), o && (i += Ke(o))), E += $.length, f = g, g = p.next();
17242
+ }
17243
+ return i;
17244
+ };
17245
+ function J(e, r, s) {
17246
+ return String(e).normalize().replaceAll(`\r
17247
+ `, `
17248
+ `).split(`
17249
+ `).map((i) => It2(i, r, s)).join(`
17250
+ `);
17251
+ }
17252
+ var bt2 = (e, r, s, i, a) => {
17253
+ let o = r, u = 0;
17254
+ for (let l = s;l < i; l++) {
17255
+ const n = e[l];
17256
+ if (o = o - n.length, u++, o <= a)
17257
+ break;
17258
+ }
17259
+ return { lineCount: o, removals: u };
17260
+ };
17261
+ var X2 = ({ cursor: e, options: r, style: s, output: i = process.stdout, maxItems: a = Number.POSITIVE_INFINITY, columnPadding: o = 0, rowPadding: u = 4 }) => {
17262
+ const l = rt(i) - o, n = nt(i), c = import_node_util2.styleText("dim", "..."), p = Math.max(n - u, 0), f = Math.max(Math.min(a, p), 5);
17263
+ let g = 0;
17264
+ e >= f - 3 && (g = Math.max(Math.min(e - f + 3, r.length - f), 0));
17265
+ let E = f < r.length && g > 0, $ = f < r.length && g + f < r.length;
17266
+ const m = Math.min(g + f, r.length), d = [];
17267
+ let F = 0;
17268
+ E && F++, $ && F++;
17269
+ const y2 = g + (E ? 1 : 0), v = m - ($ ? 1 : 0);
17270
+ for (let A = y2;A < v; A++) {
17271
+ const b = J(s(r[A], A === e), l, { hard: true, trim: false }).split(`
17272
+ `);
17273
+ d.push(b), F += b.length;
17274
+ }
17275
+ if (F > p) {
17276
+ let A = 0, b = 0, w = F;
17277
+ const S2 = e - y2, T2 = (M2, O2) => bt2(d, w, M2, O2, p);
17278
+ E ? ({ lineCount: w, removals: A } = T2(0, S2), w > p && ({ lineCount: w, removals: b } = T2(S2 + 1, d.length))) : ({ lineCount: w, removals: b } = T2(S2 + 1, d.length), w > p && ({ lineCount: w, removals: A } = T2(0, S2))), A > 0 && (E = true, d.splice(0, A)), b > 0 && ($ = true, d.splice(d.length - b, b));
17279
+ }
17280
+ const C = [];
17281
+ E && C.push(c);
17282
+ for (const A of d)
17283
+ for (const b of A)
17284
+ C.push(b);
17285
+ return $ && C.push(c), C;
17286
+ };
17030
17287
  var Rt = (e) => {
17031
17288
  const r = e.active ?? "Yes", s = e.inactive ?? "No";
17032
17289
  return new kt({ active: r, inactive: s, signal: e.signal, input: e.input, output: e.output, initialValue: e.initialValue ?? true, render() {
@@ -17073,6 +17330,51 @@ ${import_node_util2.styleText("gray", x2)} ` : "";
17073
17330
  `);
17074
17331
  };
17075
17332
  var ze = { light: I2("─", "-"), heavy: I2("━", "="), block: I2("█", "#") };
17333
+ var oe = (e, r) => e.includes(`
17334
+ `) ? e.split(`
17335
+ `).map((s) => r(s)).join(`
17336
+ `) : r(e);
17337
+ var Jt = (e) => {
17338
+ const r = (s, i) => {
17339
+ const a = s.label ?? String(s.value);
17340
+ switch (i) {
17341
+ case "disabled":
17342
+ return `${import_node_util2.styleText("gray", H2)} ${oe(a, (o) => import_node_util2.styleText("gray", o))}${s.hint ? ` ${import_node_util2.styleText("dim", `(${s.hint ?? "disabled"})`)}` : ""}`;
17343
+ case "selected":
17344
+ return `${oe(a, (o) => import_node_util2.styleText("dim", o))}`;
17345
+ case "active":
17346
+ return `${import_node_util2.styleText("green", z2)} ${a}${s.hint ? ` ${import_node_util2.styleText("dim", `(${s.hint})`)}` : ""}`;
17347
+ case "cancelled":
17348
+ return `${oe(a, (o) => import_node_util2.styleText(["strikethrough", "dim"], o))}`;
17349
+ default:
17350
+ return `${import_node_util2.styleText("dim", H2)} ${oe(a, (o) => import_node_util2.styleText("dim", o))}`;
17351
+ }
17352
+ };
17353
+ return new Tt({ options: e.options, signal: e.signal, input: e.input, output: e.output, initialValue: e.initialValue, render() {
17354
+ const s = e.withGuide ?? _.withGuide, i = `${W2(this.state)} `, a = `${ve(this.state)} `, o = Bt(e.output, e.message, a, i), u = `${s ? `${import_node_util2.styleText("gray", h)}
17355
+ ` : ""}${o}
17356
+ `;
17357
+ switch (this.state) {
17358
+ case "submit": {
17359
+ const l = s ? `${import_node_util2.styleText("gray", h)} ` : "", n = Bt(e.output, r(this.options[this.cursor], "selected"), l);
17360
+ return `${u}${n}`;
17361
+ }
17362
+ case "cancel": {
17363
+ const l = s ? `${import_node_util2.styleText("gray", h)} ` : "", n = Bt(e.output, r(this.options[this.cursor], "cancelled"), l);
17364
+ return `${u}${n}${s ? `
17365
+ ${import_node_util2.styleText("gray", h)}` : ""}`;
17366
+ }
17367
+ default: {
17368
+ const l = s ? `${import_node_util2.styleText("cyan", h)} ` : "", n = s ? import_node_util2.styleText("cyan", x2) : "", c = u.split(`
17369
+ `).length, p = s ? 2 : 1;
17370
+ return `${u}${l}${X2({ output: e.output, cursor: this.cursor, options: this.options, maxItems: e.maxItems, columnPadding: l.length, rowPadding: c + p, style: (f, g) => r(f, f.disabled ? "disabled" : g ? "active" : "inactive") }).join(`
17371
+ ${l}`)}
17372
+ ${n}
17373
+ `;
17374
+ }
17375
+ }
17376
+ } }).prompt();
17377
+ };
17076
17378
  var Qe = `${import_node_util2.styleText("gray", h)} `;
17077
17379
 
17078
17380
  // ui.ts
@@ -17094,9 +17396,9 @@ function usage(exitCode = 1) {
17094
17396
  ${BOLD}oathbound${RESET} — install, verify, and publish skills & agents
17095
17397
 
17096
17398
  ${DIM}Usage:${RESET}
17097
- oathbound init ${DIM}Setup wizard configure project${RESET}
17098
- oathbound pull <namespace/skill-name[@version]>
17099
- oathbound install <namespace/skill-name[@version]>
17399
+ oathbound init [--global|--local] ${DIM}Setup wizard (default: global + local)${RESET}
17400
+ oathbound pull <namespace/skill-name[@version]> [--global]
17401
+ oathbound install <namespace/skill-name[@version]> [--global]
17100
17402
  oathbound push [path] [--private] ${DIM}Publish a skill to the registry${RESET}
17101
17403
  oathbound search [query] ${DIM}Search skills in the registry${RESET}
17102
17404
  oathbound list ${DIM}List all public skills${RESET}
@@ -17256,8 +17558,9 @@ function hasOathboundHooks(settings) {
17256
17558
  }
17257
17559
  return false;
17258
17560
  }
17259
- function mergeClaudeSettings() {
17260
- const claudeDir = import_node_path.join(process.cwd(), ".claude");
17561
+ function mergeClaudeSettings(targetDir) {
17562
+ const baseDir = targetDir ?? process.cwd();
17563
+ const claudeDir = import_node_path.join(baseDir, ".claude");
17261
17564
  const settingsPath = import_node_path.join(claudeDir, "settings.json");
17262
17565
  if (!import_node_fs.existsSync(settingsPath)) {
17263
17566
  import_node_fs.mkdirSync(claudeDir, { recursive: true });
@@ -17283,6 +17586,16 @@ function mergeClaudeSettings() {
17283
17586
  `);
17284
17587
  return "merged";
17285
17588
  }
17589
+ function settingsHaveOathboundHooks(settingsPath) {
17590
+ if (!import_node_fs.existsSync(settingsPath))
17591
+ return false;
17592
+ try {
17593
+ const settings = JSON.parse(import_node_fs.readFileSync(settingsPath, "utf-8"));
17594
+ return hasOathboundHooks(settings);
17595
+ } catch {
17596
+ return false;
17597
+ }
17598
+ }
17286
17599
 
17287
17600
  // update.ts
17288
17601
  var import_node_fs2 = require("node:fs");
@@ -17380,8 +17693,8 @@ function compareSemver(a, b) {
17380
17693
  }
17381
17694
 
17382
17695
  // verify.ts
17383
- var import_node_fs4 = require("node:fs");
17384
- var import_node_path4 = require("node:path");
17696
+ var import_node_fs5 = require("node:fs");
17697
+ var import_node_path5 = require("node:path");
17385
17698
  var import_node_os2 = require("node:os");
17386
17699
  var import_yaml = __toESM(require_dist(), 1);
17387
17700
 
@@ -17424,9 +17737,66 @@ function hashSkillDir(skillDir) {
17424
17737
  return contentHash(files);
17425
17738
  }
17426
17739
 
17740
+ // project-setup.ts
17741
+ var import_node_child_process = require("node:child_process");
17742
+ var import_node_fs4 = require("node:fs");
17743
+ var import_node_path4 = require("node:path");
17744
+ function detectPackageManager() {
17745
+ if (import_node_fs4.existsSync(import_node_path4.join(process.cwd(), "bun.lockb")) || import_node_fs4.existsSync(import_node_path4.join(process.cwd(), "bun.lock")))
17746
+ return "bun";
17747
+ if (import_node_fs4.existsSync(import_node_path4.join(process.cwd(), "pnpm-lock.yaml")))
17748
+ return "pnpm";
17749
+ if (import_node_fs4.existsSync(import_node_path4.join(process.cwd(), "yarn.lock")))
17750
+ return "yarn";
17751
+ return "npm";
17752
+ }
17753
+ function installDevDependency() {
17754
+ const pkgPath = import_node_path4.join(process.cwd(), "package.json");
17755
+ if (!import_node_fs4.existsSync(pkgPath))
17756
+ return "no-package-json";
17757
+ try {
17758
+ const pkg = JSON.parse(import_node_fs4.readFileSync(pkgPath, "utf-8"));
17759
+ if (pkg.devDependencies?.oathbound || pkg.dependencies?.oathbound)
17760
+ return "skipped";
17761
+ } catch {}
17762
+ const pm = detectPackageManager();
17763
+ const cmds = {
17764
+ bun: ["bun", ["add", "--dev", "oathbound"]],
17765
+ pnpm: ["pnpm", ["add", "--save-dev", "oathbound"]],
17766
+ yarn: ["yarn", ["add", "--dev", "oathbound"]],
17767
+ npm: ["npm", ["install", "--save-dev", "oathbound"]]
17768
+ };
17769
+ const [bin, args] = cmds[pm];
17770
+ try {
17771
+ import_node_child_process.execFileSync(bin, args, { stdio: "pipe", cwd: process.cwd() });
17772
+ return "installed";
17773
+ } catch {
17774
+ return "failed";
17775
+ }
17776
+ }
17777
+ function addPrepareScript() {
17778
+ const pkgPath = import_node_path4.join(process.cwd(), "package.json");
17779
+ if (!import_node_fs4.existsSync(pkgPath))
17780
+ return "skipped";
17781
+ let pkg;
17782
+ try {
17783
+ pkg = JSON.parse(import_node_fs4.readFileSync(pkgPath, "utf-8"));
17784
+ } catch {
17785
+ return "skipped";
17786
+ }
17787
+ const prepare = pkg.scripts?.prepare ?? "";
17788
+ if (prepare.includes("oathbound setup"))
17789
+ return "skipped";
17790
+ const newPrepare = prepare ? `${prepare} && oathbound setup` : "oathbound setup";
17791
+ pkg.scripts = { ...pkg.scripts ?? {}, prepare: newPrepare };
17792
+ import_node_fs4.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + `
17793
+ `);
17794
+ return prepare ? "appended" : "added";
17795
+ }
17796
+
17427
17797
  // verify.ts
17428
17798
  function sessionStatePath(sessionId) {
17429
- return import_node_path4.join(import_node_os2.tmpdir(), `oathbound-${sessionId}.json`);
17799
+ return import_node_path5.join(import_node_os2.tmpdir(), `oathbound-${sessionId}.json`);
17430
17800
  }
17431
17801
  async function readStdin() {
17432
17802
  const chunks = [];
@@ -17435,45 +17805,113 @@ async function readStdin() {
17435
17805
  }
17436
17806
  return Buffer.concat(chunks).toString("utf-8");
17437
17807
  }
17438
- function findSkillsDir() {
17808
+ function resolveLocalSkillsDir() {
17439
17809
  const cwd = process.cwd();
17440
17810
  const normalized = cwd.replace(/\/+$/, "");
17441
17811
  if (normalized.endsWith(".claude/skills"))
17442
17812
  return cwd;
17443
17813
  if (normalized.endsWith(".claude")) {
17444
- const skills = import_node_path4.join(cwd, "skills");
17445
- if (import_node_fs4.existsSync(skills))
17814
+ const skills = import_node_path5.join(cwd, "skills");
17815
+ if (import_node_fs5.existsSync(skills))
17446
17816
  return skills;
17447
17817
  }
17448
- const direct = import_node_path4.join(cwd, ".claude", "skills");
17449
- if (import_node_fs4.existsSync(direct))
17818
+ const direct = import_node_path5.join(cwd, ".claude", "skills");
17819
+ if (import_node_fs5.existsSync(direct))
17450
17820
  return direct;
17451
17821
  const SKIP = new Set(["node_modules", ".git", "dist", "build", ".next"]);
17452
17822
  function search(dir, depth) {
17453
17823
  if (depth <= 0)
17454
17824
  return null;
17455
17825
  try {
17456
- const entries = import_node_fs4.readdirSync(dir, { withFileTypes: true });
17826
+ const entries = import_node_fs5.readdirSync(dir, { withFileTypes: true });
17457
17827
  for (const entry of entries) {
17458
17828
  if (!entry.isDirectory() || SKIP.has(entry.name))
17459
17829
  continue;
17460
17830
  if (entry.name === ".claude") {
17461
- const skills = import_node_path4.join(dir, ".claude", "skills");
17462
- if (import_node_fs4.existsSync(skills))
17831
+ const skills = import_node_path5.join(dir, ".claude", "skills");
17832
+ if (import_node_fs5.existsSync(skills))
17463
17833
  return skills;
17464
17834
  }
17465
17835
  }
17466
17836
  for (const entry of entries) {
17467
17837
  if (!entry.isDirectory() || SKIP.has(entry.name) || entry.name.startsWith("."))
17468
17838
  continue;
17469
- const result = search(import_node_path4.join(dir, entry.name), depth - 1);
17839
+ const result = search(import_node_path5.join(dir, entry.name), depth - 1);
17470
17840
  if (result)
17471
17841
  return result;
17472
17842
  }
17473
17843
  } catch {}
17474
17844
  return null;
17475
17845
  }
17476
- return search(cwd, 5) ?? cwd;
17846
+ return search(cwd, 5);
17847
+ }
17848
+ function hasSkillSubdirs(dir) {
17849
+ try {
17850
+ const entries = import_node_fs5.readdirSync(dir, { withFileTypes: true });
17851
+ return entries.some((e) => e.isDirectory() && !e.name.startsWith("."));
17852
+ } catch {
17853
+ return false;
17854
+ }
17855
+ }
17856
+ function findSkillsDirs() {
17857
+ const results = [];
17858
+ const globalDir = import_node_path5.join(import_node_os2.homedir(), ".claude", "skills");
17859
+ if (import_node_fs5.existsSync(globalDir) && hasSkillSubdirs(globalDir)) {
17860
+ results.push({ path: globalDir, source: "global" });
17861
+ }
17862
+ const localDir = resolveLocalSkillsDir();
17863
+ if (localDir && hasSkillSubdirs(localDir)) {
17864
+ results.push({ path: localDir, source: "local" });
17865
+ }
17866
+ return results;
17867
+ }
17868
+ function propagateToProject(version3) {
17869
+ try {
17870
+ const cwd = process.cwd();
17871
+ const localSkills = import_node_path5.join(cwd, ".claude", "skills");
17872
+ if (!import_node_fs5.existsSync(localSkills))
17873
+ return;
17874
+ if (!hasSkillSubdirs(localSkills))
17875
+ return;
17876
+ if (import_node_fs5.existsSync(import_node_path5.join(cwd, ".oathbound.jsonc")))
17877
+ return;
17878
+ const pkgPath = import_node_path5.join(cwd, "package.json");
17879
+ if (!import_node_fs5.existsSync(pkgPath))
17880
+ return;
17881
+ writeOathboundConfig("warn");
17882
+ const raw = import_node_fs5.readFileSync(pkgPath, "utf-8");
17883
+ const pkg = JSON.parse(raw);
17884
+ if (!pkg.devDependencies?.oathbound && !pkg.dependencies?.oathbound) {
17885
+ pkg.devDependencies = { ...pkg.devDependencies ?? {}, oathbound: `^${version3}` };
17886
+ const indent = raw.match(/^(\s+)/m)?.[1]?.length ?? 2;
17887
+ import_node_fs5.writeFileSync(pkgPath, JSON.stringify(pkg, null, indent) + `
17888
+ `);
17889
+ }
17890
+ addPrepareScript();
17891
+ mergeClaudeSettings();
17892
+ process.stderr.write(`
17893
+ Oathbound: configured project for team verification.
17894
+ `);
17895
+ process.stderr.write(` Created .oathbound.jsonc
17896
+ `);
17897
+ process.stderr.write(` Added oathbound to devDependencies
17898
+ `);
17899
+ process.stderr.write(` Added prepare script to package.json
17900
+
17901
+ `);
17902
+ process.stderr.write(` Commit these changes to protect your team:
17903
+ `);
17904
+ process.stderr.write(` git add .oathbound.jsonc package.json .claude/settings.json
17905
+
17906
+ `);
17907
+ process.stderr.write(` Then run: npm install (or bun/pnpm install)
17908
+
17909
+ `);
17910
+ } catch (err) {
17911
+ const msg = err instanceof Error ? err.message : "Unknown error";
17912
+ process.stderr.write(`oathbound: auto-propagation warning: ${msg}
17913
+ `);
17914
+ }
17477
17915
  }
17478
17916
  function skillNameFromPath(filePath) {
17479
17917
  const marker = ".claude/skills/";
@@ -17516,30 +17954,34 @@ ${TEAL}${BOLD}⬡ oathbound${RESET} ${YELLOW}⚠ Warning:${RESET} skill ${BOLD}"
17516
17954
  `);
17517
17955
  process.exit(0);
17518
17956
  }
17519
- function isExternalSkillAccess(toolName, toolInput, skillsDir, baseName) {
17520
- const resolvedSkillsDir = import_node_path4.resolve(skillsDir);
17957
+ function isExternalSkillAccess(toolName, toolInput, knownDirs, baseName) {
17958
+ const resolvedDirs = knownDirs.map((d) => import_node_path5.resolve(d));
17959
+ const isUnderKnownDir = (p) => {
17960
+ const rp = import_node_path5.resolve(p);
17961
+ return resolvedDirs.some((d) => rp.startsWith(d));
17962
+ };
17521
17963
  if (toolName === "Read") {
17522
17964
  const p = String(toolInput.file_path ?? "");
17523
- if (p && !import_node_path4.resolve(p).startsWith(resolvedSkillsDir))
17965
+ if (p && !isUnderKnownDir(p))
17524
17966
  return true;
17525
17967
  }
17526
17968
  if (toolName === "Glob" || toolName === "Grep") {
17527
17969
  const p = String(toolInput.path ?? "");
17528
- if (p && !import_node_path4.resolve(p).startsWith(resolvedSkillsDir))
17970
+ if (p && !isUnderKnownDir(p))
17529
17971
  return true;
17530
17972
  }
17531
17973
  if (toolName === "Bash") {
17532
17974
  const cmd = String(toolInput.command ?? "");
17533
- if (cmd.includes("/.claude/skills/" + baseName) && !cmd.includes(resolvedSkillsDir))
17975
+ if (cmd.includes("/.claude/skills/" + baseName) && !resolvedDirs.some((d) => cmd.includes(d)))
17534
17976
  return true;
17535
17977
  }
17536
17978
  return false;
17537
17979
  }
17538
17980
  function parseSkillVersion(skillDir) {
17539
- const skillMdPath = import_node_path4.join(skillDir, "SKILL.md");
17540
- if (!import_node_fs4.existsSync(skillMdPath))
17981
+ const skillMdPath = import_node_path5.join(skillDir, "SKILL.md");
17982
+ if (!import_node_fs5.existsSync(skillMdPath))
17541
17983
  return null;
17542
- const content = import_node_fs4.readFileSync(skillMdPath, "utf-8");
17984
+ const content = import_node_fs5.readFileSync(skillMdPath, "utf-8");
17543
17985
  const match = content.match(/^---\s*\n([\s\S]*?)\n---\s*\n/);
17544
17986
  if (!match)
17545
17987
  return null;
@@ -17554,7 +17996,7 @@ function parseSkillVersion(skillDir) {
17554
17996
  return null;
17555
17997
  }
17556
17998
  }
17557
- async function verify(supabaseUrl, supabaseAnonKey) {
17999
+ async function verify(supabaseUrl, supabaseAnonKey, version3) {
17558
18000
  let input;
17559
18001
  try {
17560
18002
  input = JSON.parse(await readStdin());
@@ -17569,28 +18011,32 @@ async function verify(supabaseUrl, supabaseAnonKey) {
17569
18011
  `);
17570
18012
  process.exit(1);
17571
18013
  }
17572
- const skillsDir = findSkillsDir();
17573
- if (!skillsDir.endsWith(".claude/skills") && !skillsDir.includes(".claude/skills")) {
18014
+ const skillsDirs = findSkillsDirs();
18015
+ propagateToProject(version3);
18016
+ if (skillsDirs.length === 0) {
17574
18017
  const state2 = { verified: {}, rejected: [], ok: true };
17575
- import_node_fs4.writeFileSync(sessionStatePath(sessionId), JSON.stringify(state2));
17576
- console.log(JSON.stringify({ hookSpecificOutput: { hookEventName: "SessionStart", additionalContext: "Oathbound: no .claude/skills/ directory found — nothing to verify." } }));
18018
+ import_node_fs5.writeFileSync(sessionStatePath(sessionId), JSON.stringify(state2));
18019
+ console.log(JSON.stringify({ hookSpecificOutput: { hookEventName: "SessionStart", additionalContext: "Oathbound: no skills found — nothing to verify." } }));
17577
18020
  process.exit(0);
17578
18021
  }
17579
- const entries = import_node_fs4.readdirSync(skillsDir, { withFileTypes: true });
17580
- const skillDirs = entries.filter((e) => e.isDirectory() && !e.name.startsWith("."));
17581
- if (skillDirs.length === 0) {
18022
+ const localSkills = {};
18023
+ for (const { path: dir } of skillsDirs) {
18024
+ const entries = import_node_fs5.readdirSync(dir, { withFileTypes: true });
18025
+ for (const e of entries.filter((e2) => e2.isDirectory() && !e2.name.startsWith("."))) {
18026
+ const fullPath = import_node_path5.join(dir, e.name);
18027
+ localSkills[e.name] = {
18028
+ hash: hashSkillDir(fullPath),
18029
+ version: parseSkillVersion(fullPath) ?? "1.0.0",
18030
+ dir: fullPath
18031
+ };
18032
+ }
18033
+ }
18034
+ if (Object.keys(localSkills).length === 0) {
17582
18035
  const state2 = { verified: {}, rejected: [], ok: true };
17583
- import_node_fs4.writeFileSync(sessionStatePath(sessionId), JSON.stringify(state2));
18036
+ import_node_fs5.writeFileSync(sessionStatePath(sessionId), JSON.stringify(state2));
17584
18037
  console.log(JSON.stringify({ hookSpecificOutput: { hookEventName: "SessionStart", additionalContext: "Oathbound: no skills installed — nothing to verify." } }));
17585
18038
  process.exit(0);
17586
18039
  }
17587
- const localSkills = {};
17588
- for (const dir of skillDirs) {
17589
- const fullPath = import_node_path4.join(skillsDir, dir.name);
17590
- const hash = hashSkillDir(fullPath);
17591
- const version3 = parseSkillVersion(fullPath) ?? "1.0.0";
17592
- localSkills[dir.name] = { hash, version: version3 };
17593
- }
17594
18040
  const config = readOathboundConfig();
17595
18041
  const enforcement = config?.enforcement ?? "warn";
17596
18042
  const supabase = createClient(supabaseUrl, supabaseAnonKey);
@@ -17619,11 +18065,11 @@ async function verify(supabaseUrl, supabaseAnonKey) {
17619
18065
  const warnings = [];
17620
18066
  process.stderr.write(`${BRAND} ${TEAL}verifying skills...${RESET}
17621
18067
  `);
17622
- for (const [name, { hash: localHash, version: version3 }] of Object.entries(localSkills)) {
18068
+ for (const [name, { hash: localHash, version: version4 }] of Object.entries(localSkills)) {
17623
18069
  const versionMap = registryMap.get(name);
17624
- const entry = versionMap?.get(version3);
18070
+ const entry = versionMap?.get(version4);
17625
18071
  if (!entry) {
17626
- process.stderr.write(`${DIM} ${name}@${version3}: ${localHash} (not in registry)${RESET}
18072
+ process.stderr.write(`${DIM} ${name}@${version4}: ${localHash} (not in registry)${RESET}
17627
18073
  `);
17628
18074
  if (enforcement === "warn") {
17629
18075
  warnings.push({ name, reason: "not in registry" });
@@ -17632,7 +18078,7 @@ async function verify(supabaseUrl, supabaseAnonKey) {
17632
18078
  rejected.push({ name, reason: "not in registry" });
17633
18079
  }
17634
18080
  } else if (localHash !== entry.hash) {
17635
- process.stderr.write(`${RED} ${name}@${version3}: ${localHash} ≠ ${entry.hash}${RESET}
18081
+ process.stderr.write(`${RED} ${name}@${version4}: ${localHash} ≠ ${entry.hash}${RESET}
17636
18082
  `);
17637
18083
  if (enforcement === "warn") {
17638
18084
  warnings.push({ name, reason: `content hash mismatch (local: ${localHash.slice(0, 8)}…, registry: ${entry.hash.slice(0, 8)}…)` });
@@ -17641,18 +18087,22 @@ async function verify(supabaseUrl, supabaseAnonKey) {
17641
18087
  rejected.push({ name, reason: `content hash mismatch (local: ${localHash.slice(0, 8)}…, registry: ${entry.hash.slice(0, 8)}…)` });
17642
18088
  }
17643
18089
  } else if (enforcement === "audited" && !entry.audited) {
17644
- process.stderr.write(`${YELLOW} ${name}@${version3}: ${localHash} (registered but not audited)${RESET}
18090
+ process.stderr.write(`${YELLOW} ${name}@${version4}: ${localHash} (registered but not audited)${RESET}
17645
18091
  `);
17646
18092
  rejected.push({ name, reason: "no passed audit" });
17647
18093
  } else {
17648
- process.stderr.write(`${GREEN} ${name}@${version3}: ${localHash} ✓${RESET}
18094
+ process.stderr.write(`${GREEN} ${name}@${version4}: ${localHash} ✓${RESET}
17649
18095
  `);
17650
18096
  verified[name] = localHash;
17651
18097
  }
17652
18098
  }
17653
18099
  const ok = rejected.length === 0;
17654
- const state = { verified, rejected, ok };
17655
- import_node_fs4.writeFileSync(sessionStatePath(sessionId), JSON.stringify(state));
18100
+ const skillDirsMap = {};
18101
+ for (const [name, { dir }] of Object.entries(localSkills)) {
18102
+ skillDirsMap[name] = dir;
18103
+ }
18104
+ const state = { verified, rejected, ok, skillDirs: skillDirsMap };
18105
+ import_node_fs5.writeFileSync(sessionStatePath(sessionId), JSON.stringify(state));
17656
18106
  if (ok && warnings.length === 0) {
17657
18107
  const names = Object.keys(verified).join(", ");
17658
18108
  console.log(JSON.stringify({
@@ -17726,23 +18176,42 @@ async function verifyCheck() {
17726
18176
  process.exit(0);
17727
18177
  const config = readOathboundConfig();
17728
18178
  const enforcement = config?.enforcement ?? "warn";
17729
- const skillsDir = findSkillsDir();
17730
- if (isExternalSkillAccess(toolName, toolInput, skillsDir, baseName)) {
17731
- process.exit(0);
17732
- }
17733
18179
  const stateFile = sessionStatePath(sessionId);
17734
- if (!import_node_fs4.existsSync(stateFile))
18180
+ if (!import_node_fs5.existsSync(stateFile))
17735
18181
  process.exit(0);
17736
18182
  let state;
17737
18183
  try {
17738
- state = JSON.parse(import_node_fs4.readFileSync(stateFile, "utf-8"));
18184
+ state = JSON.parse(import_node_fs5.readFileSync(stateFile, "utf-8"));
17739
18185
  } catch {
17740
18186
  process.stderr.write(`oathbound verify --check: corrupt session state file
17741
18187
  `);
17742
18188
  process.exit(1);
17743
18189
  }
17744
- const skillDir = import_node_path4.join(skillsDir, baseName);
17745
- if (!import_node_fs4.existsSync(skillDir) || !import_node_fs4.statSync(skillDir).isDirectory()) {
18190
+ let skillDir = null;
18191
+ if (state.skillDirs?.[baseName]) {
18192
+ skillDir = state.skillDirs[baseName];
18193
+ } else {
18194
+ for (const { path: dir } of findSkillsDirs()) {
18195
+ const candidate = import_node_path5.join(dir, baseName);
18196
+ if (import_node_fs5.existsSync(candidate) && import_node_fs5.statSync(candidate).isDirectory()) {
18197
+ skillDir = candidate;
18198
+ }
18199
+ }
18200
+ }
18201
+ const knownDirs = [];
18202
+ if (state.skillDirs) {
18203
+ const parentDirs = new Set;
18204
+ for (const d of Object.values(state.skillDirs)) {
18205
+ parentDirs.add(import_node_path5.join(d, ".."));
18206
+ }
18207
+ knownDirs.push(...parentDirs);
18208
+ } else {
18209
+ knownDirs.push(...findSkillsDirs().map((e) => e.path));
18210
+ }
18211
+ if (knownDirs.length > 0 && isExternalSkillAccess(toolName, toolInput, knownDirs, baseName)) {
18212
+ process.exit(0);
18213
+ }
18214
+ if (!skillDir || !import_node_fs5.existsSync(skillDir) || !import_node_fs5.statSync(skillDir).isDirectory()) {
17746
18215
  if (enforcement === "warn") {
17747
18216
  warnSkill(baseName, "not installed locally");
17748
18217
  } else {
@@ -17771,38 +18240,38 @@ async function verifyCheck() {
17771
18240
  }
17772
18241
 
17773
18242
  // auth.ts
17774
- var import_node_child_process = require("node:child_process");
17775
- var import_node_fs5 = require("node:fs");
18243
+ var import_node_child_process2 = require("node:child_process");
18244
+ var import_node_fs6 = require("node:fs");
17776
18245
  var import_node_http = require("node:http");
17777
- var import_node_path5 = require("node:path");
18246
+ var import_node_path6 = require("node:path");
17778
18247
  var import_node_os3 = require("node:os");
17779
18248
  var SUPABASE_URL = "https://mjnfqagwuewhgwbtrdgs.supabase.co";
17780
18249
  var SUPABASE_ANON_KEY = "sb_publishable_T-rk0azNRqAMLLGCyadyhQ_ulk9685n";
17781
18250
  var API_BASE = process.env.OATHBOUND_API_URL ?? "https://www.oathbound.ai";
17782
- var AUTH_DIR = import_node_path5.join(import_node_os3.homedir(), ".oathbound");
17783
- var AUTH_FILE = import_node_path5.join(AUTH_DIR, "auth.json");
18251
+ var AUTH_DIR = import_node_path6.join(import_node_os3.homedir(), ".oathbound");
18252
+ var AUTH_FILE = import_node_path6.join(AUTH_DIR, "auth.json");
17784
18253
  function saveSession(session) {
17785
- import_node_fs5.mkdirSync(AUTH_DIR, { recursive: true, mode: 448 });
17786
- import_node_fs5.writeFileSync(AUTH_FILE, JSON.stringify(session, null, 2), { mode: 384 });
18254
+ import_node_fs6.mkdirSync(AUTH_DIR, { recursive: true, mode: 448 });
18255
+ import_node_fs6.writeFileSync(AUTH_FILE, JSON.stringify(session, null, 2), { mode: 384 });
17787
18256
  }
17788
18257
  function loadSession() {
17789
- if (!import_node_fs5.existsSync(AUTH_FILE))
18258
+ if (!import_node_fs6.existsSync(AUTH_FILE))
17790
18259
  return null;
17791
18260
  try {
17792
- return JSON.parse(import_node_fs5.readFileSync(AUTH_FILE, "utf-8"));
18261
+ return JSON.parse(import_node_fs6.readFileSync(AUTH_FILE, "utf-8"));
17793
18262
  } catch {
17794
18263
  return null;
17795
18264
  }
17796
18265
  }
17797
18266
  function clearSession() {
17798
- if (import_node_fs5.existsSync(AUTH_FILE))
17799
- import_node_fs5.unlinkSync(AUTH_FILE);
18267
+ if (import_node_fs6.existsSync(AUTH_FILE))
18268
+ import_node_fs6.unlinkSync(AUTH_FILE);
17800
18269
  }
17801
18270
  function openBrowser(url) {
17802
18271
  const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
17803
18272
  const args = process.platform === "win32" ? ["/c", "start", "", url] : [url];
17804
18273
  try {
17805
- import_node_child_process.spawn(cmd, args, { stdio: "ignore", detached: true }).unref();
18274
+ import_node_child_process2.spawn(cmd, args, { stdio: "ignore", detached: true }).unref();
17806
18275
  } catch {}
17807
18276
  }
17808
18277
  var SUCCESS_HTML = `<!DOCTYPE html>
@@ -17936,16 +18405,16 @@ ${BRAND}`);
17936
18405
  }
17937
18406
 
17938
18407
  // push.ts
17939
- var import_node_fs6 = require("node:fs");
17940
- var import_node_path6 = require("node:path");
18408
+ var import_node_fs7 = require("node:fs");
18409
+ var import_node_path7 = require("node:path");
17941
18410
  var import_yaml2 = __toESM(require_dist(), 1);
17942
18411
  var API_BASE2 = process.env.OATHBOUND_API_URL ?? "https://www.oathbound.ai";
17943
18412
  async function push(pathArg, options) {
17944
18413
  Wt2(BRAND);
17945
18414
  const skillDir = resolveSkillDir(pathArg);
17946
18415
  console.log(`${DIM} directory: ${skillDir}${RESET}`);
17947
- if (!import_node_fs6.existsSync(import_node_path6.join(skillDir, "SKILL.md"))) {
17948
- fail("No SKILL.md found", `Expected at ${import_node_path6.join(skillDir, "SKILL.md")}`);
18416
+ if (!import_node_fs7.existsSync(import_node_path7.join(skillDir, "SKILL.md"))) {
18417
+ fail("No SKILL.md found", `Expected at ${import_node_path7.join(skillDir, "SKILL.md")}`);
17949
18418
  }
17950
18419
  const rawFiles = collectFiles(skillDir);
17951
18420
  const skillMdFile = rawFiles.find((f) => f.path === "SKILL.md");
@@ -18017,13 +18486,13 @@ async function push(pathArg, options) {
18017
18486
  }
18018
18487
  function resolveSkillDir(pathArg) {
18019
18488
  if (pathArg) {
18020
- const resolved = import_node_path6.resolve(pathArg);
18021
- if (!import_node_fs6.existsSync(resolved) || !import_node_fs6.statSync(resolved).isDirectory()) {
18489
+ const resolved = import_node_path7.resolve(pathArg);
18490
+ if (!import_node_fs7.existsSync(resolved) || !import_node_fs7.statSync(resolved).isDirectory()) {
18022
18491
  fail("Invalid path", `${resolved} is not a directory`);
18023
18492
  }
18024
18493
  return resolved;
18025
18494
  }
18026
- if (import_node_fs6.existsSync(import_node_path6.join(process.cwd(), "SKILL.md"))) {
18495
+ if (import_node_fs7.existsSync(import_node_path7.join(process.cwd(), "SKILL.md"))) {
18027
18496
  return process.cwd();
18028
18497
  }
18029
18498
  fail("No skill directory found", "Run from within a skill directory or pass a path: oathbound push ./my-skill");
@@ -18146,8 +18615,8 @@ ${BRAND} ${TEAL}${showing}${RESET}
18146
18615
  }
18147
18616
 
18148
18617
  // agent-push.ts
18149
- var import_node_fs7 = require("node:fs");
18150
- var import_node_path7 = require("node:path");
18618
+ var import_node_fs8 = require("node:fs");
18619
+ var import_node_path8 = require("node:path");
18151
18620
  var import_yaml3 = __toESM(require_dist(), 1);
18152
18621
  var API_BASE4 = process.env.OATHBOUND_API_URL ?? "https://www.oathbound.ai";
18153
18622
  function parseAgentFrontmatter(content) {
@@ -18160,11 +18629,11 @@ function parseAgentFrontmatter(content) {
18160
18629
  }
18161
18630
  function resolveAgentFile(pathArg) {
18162
18631
  if (pathArg) {
18163
- const resolved = import_node_path7.resolve(pathArg);
18164
- if (!import_node_fs7.existsSync(resolved)) {
18632
+ const resolved = import_node_path8.resolve(pathArg);
18633
+ if (!import_node_fs8.existsSync(resolved)) {
18165
18634
  fail("File not found", resolved);
18166
18635
  }
18167
- if (import_node_fs7.statSync(resolved).isDirectory()) {
18636
+ if (import_node_fs8.statSync(resolved).isDirectory()) {
18168
18637
  return findAgentInDir(resolved);
18169
18638
  }
18170
18639
  if (!resolved.endsWith(".md")) {
@@ -18175,11 +18644,11 @@ function resolveAgentFile(pathArg) {
18175
18644
  return findAgentInDir(process.cwd());
18176
18645
  }
18177
18646
  function findAgentInDir(dir) {
18178
- const mdFiles = import_node_fs7.readdirSync(dir).filter((f) => f.endsWith(".md") && !f.startsWith(".")).map((f) => import_node_path7.join(dir, f));
18647
+ const mdFiles = import_node_fs8.readdirSync(dir).filter((f) => f.endsWith(".md") && !f.startsWith(".")).map((f) => import_node_path8.join(dir, f));
18179
18648
  const agents = [];
18180
18649
  for (const file of mdFiles) {
18181
18650
  try {
18182
- const content = import_node_fs7.readFileSync(file, "utf-8");
18651
+ const content = import_node_fs8.readFileSync(file, "utf-8");
18183
18652
  const { meta, body } = parseAgentFrontmatter(content);
18184
18653
  if (meta.name && meta.description && body.trim()) {
18185
18654
  agents.push(file);
@@ -18197,7 +18666,7 @@ function findAgentInDir(dir) {
18197
18666
  async function agentPush(pathArg, options) {
18198
18667
  Wt2(BRAND);
18199
18668
  const agentFile = resolveAgentFile(pathArg);
18200
- const content = import_node_fs7.readFileSync(agentFile, "utf-8");
18669
+ const content = import_node_fs8.readFileSync(agentFile, "utf-8");
18201
18670
  const { meta, body } = parseAgentFrontmatter(content);
18202
18671
  const name = String(meta.name ?? "");
18203
18672
  const description = String(meta.description ?? "");
@@ -18386,7 +18855,7 @@ ${BRAND} ${TEAL}${showing}${RESET}
18386
18855
  }
18387
18856
  }
18388
18857
  // cli.ts
18389
- var VERSION = "0.15.1";
18858
+ var VERSION = "0.17.0";
18390
18859
  var SUPABASE_URL2 = "https://mjnfqagwuewhgwbtrdgs.supabase.co";
18391
18860
  var SUPABASE_ANON_KEY2 = "sb_publishable_T-rk0azNRqAMLLGCyadyhQ_ulk9685n";
18392
18861
  var API_BASE6 = process.env.OATHBOUND_API_URL ?? "https://www.oathbound.ai";
@@ -18407,41 +18876,8 @@ function parseSkillArg(arg) {
18407
18876
  return null;
18408
18877
  return { namespace: arg.slice(0, slash), name, version: vStr };
18409
18878
  }
18410
- function detectPackageManager() {
18411
- if (import_node_fs8.existsSync(import_node_path8.join(process.cwd(), "bun.lockb")) || import_node_fs8.existsSync(import_node_path8.join(process.cwd(), "bun.lock")))
18412
- return "bun";
18413
- if (import_node_fs8.existsSync(import_node_path8.join(process.cwd(), "pnpm-lock.yaml")))
18414
- return "pnpm";
18415
- if (import_node_fs8.existsSync(import_node_path8.join(process.cwd(), "yarn.lock")))
18416
- return "yarn";
18417
- return "npm";
18418
- }
18419
- function installDevDependency() {
18420
- const pkgPath = import_node_path8.join(process.cwd(), "package.json");
18421
- if (!import_node_fs8.existsSync(pkgPath))
18422
- return "no-package-json";
18423
- try {
18424
- const pkg = JSON.parse(import_node_fs8.readFileSync(pkgPath, "utf-8"));
18425
- if (pkg.devDependencies?.oathbound || pkg.dependencies?.oathbound)
18426
- return "skipped";
18427
- } catch {}
18428
- const pm = detectPackageManager();
18429
- const cmds = {
18430
- bun: ["bun", ["add", "--dev", "oathbound"]],
18431
- pnpm: ["pnpm", ["add", "--save-dev", "oathbound"]],
18432
- yarn: ["yarn", ["add", "--dev", "oathbound"]],
18433
- npm: ["npm", ["install", "--save-dev", "oathbound"]]
18434
- };
18435
- const [bin, args] = cmds[pm];
18436
- try {
18437
- import_node_child_process2.execFileSync(bin, args, { stdio: "pipe", cwd: process.cwd() });
18438
- return "installed";
18439
- } catch {
18440
- return "failed";
18441
- }
18442
- }
18443
18879
  function setup() {
18444
- if (!import_node_fs8.existsSync(import_node_path8.join(process.cwd(), ".oathbound.jsonc")))
18880
+ if (!import_node_fs9.existsSync(import_node_path9.join(process.cwd(), ".oathbound.jsonc")))
18445
18881
  return;
18446
18882
  const result = mergeClaudeSettings();
18447
18883
  if (result === "malformed") {
@@ -18450,27 +18886,31 @@ function setup() {
18450
18886
  process.exit(1);
18451
18887
  }
18452
18888
  }
18453
- function addPrepareScript() {
18454
- const pkgPath = import_node_path8.join(process.cwd(), "package.json");
18455
- if (!import_node_fs8.existsSync(pkgPath))
18456
- return "skipped";
18457
- let pkg;
18458
- try {
18459
- pkg = JSON.parse(import_node_fs8.readFileSync(pkgPath, "utf-8"));
18460
- } catch {
18461
- return "skipped";
18462
- }
18463
- const prepare = pkg.scripts?.prepare ?? "";
18464
- if (prepare.includes("oathbound setup"))
18465
- return "skipped";
18466
- const newPrepare = prepare ? `${prepare} && oathbound setup` : "oathbound setup";
18467
- pkg.scripts = { ...pkg.scripts ?? {}, prepare: newPrepare };
18468
- import_node_fs8.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + `
18889
+ function initGlobal() {
18890
+ const home = import_node_os4.homedir();
18891
+ const mergeResult = mergeClaudeSettings(home);
18892
+ switch (mergeResult) {
18893
+ case "created":
18894
+ process.stderr.write(`${GREEN} ✓ Created ~/.claude/settings.json with hooks${RESET}
18469
18895
  `);
18470
- return prepare ? "appended" : "added";
18896
+ break;
18897
+ case "merged":
18898
+ process.stderr.write(`${GREEN} ✓ Added hooks to ~/.claude/settings.json${RESET}
18899
+ `);
18900
+ break;
18901
+ case "skipped":
18902
+ process.stderr.write(`${DIM} ~/.claude/settings.json already has oathbound hooks — skipped${RESET}
18903
+ `);
18904
+ break;
18905
+ case "malformed":
18906
+ process.stderr.write(`${RED} ✗ ~/.claude/settings.json is malformed JSON — skipped${RESET}
18907
+ `);
18908
+ process.stderr.write(`${RED} Please fix the file manually and re-run oathbound init --global${RESET}
18909
+ `);
18910
+ break;
18911
+ }
18471
18912
  }
18472
- async function init() {
18473
- Wt2(BRAND);
18913
+ async function initLocal() {
18474
18914
  const level = "warn";
18475
18915
  let installResult = installDevDependency();
18476
18916
  if (installResult === "no-package-json") {
@@ -18481,8 +18921,8 @@ async function init() {
18481
18921
  Nt("Please run `npx oathbound init` inside of the folder where you want to run Claude Code. Oathbound currently needs an NPM package in order to run.");
18482
18922
  process.exit(1);
18483
18923
  }
18484
- const dirName = import_node_path8.basename(process.cwd()).toLowerCase().replace(/[^a-z0-9._-]/g, "-").replace(/^[._]+/, "").replace(/-+/g, "-") || "project";
18485
- import_node_fs8.writeFileSync(import_node_path8.join(process.cwd(), "package.json"), JSON.stringify({
18924
+ const dirName = import_node_path9.basename(process.cwd()).toLowerCase().replace(/[^a-z0-9._-]/g, "-").replace(/^[._]+/, "").replace(/-+/g, "-") || "project";
18925
+ import_node_fs9.writeFileSync(import_node_path9.join(process.cwd(), "package.json"), JSON.stringify({
18486
18926
  name: dirName,
18487
18927
  private: true,
18488
18928
  scripts: { prepare: "oathbound setup" }
@@ -18544,14 +18984,59 @@ async function init() {
18544
18984
  `);
18545
18985
  break;
18546
18986
  }
18987
+ }
18988
+ async function init(options = {}) {
18989
+ Wt2(BRAND);
18990
+ if (options.global && !options.local) {
18991
+ initGlobal();
18992
+ } else if (options.local && !options.global) {
18993
+ await initLocal();
18994
+ } else {
18995
+ initGlobal();
18996
+ await initLocal();
18997
+ }
18547
18998
  Gt(`\uD83C\uDF89 Oath Bound set up complete!`);
18548
18999
  }
18549
- async function pull(skillArg) {
19000
+ async function ensureInitialized() {
19001
+ const globalSettings = import_node_path9.join(import_node_os4.homedir(), ".claude", "settings.json");
19002
+ const localSettings = import_node_path9.join(process.cwd(), ".claude", "settings.json");
19003
+ if (settingsHaveOathboundHooks(globalSettings) || settingsHaveOathboundHooks(localSettings)) {
19004
+ return;
19005
+ }
19006
+ if (!process.stdin.isTTY) {
19007
+ process.stderr.write("oathbound: no hooks configured. Run `npx oathbound init` first.\n");
19008
+ process.exit(1);
19009
+ }
19010
+ process.stderr.write(`
19011
+ ${BRAND} ${YELLOW}No oathbound hooks detected.${RESET}
19012
+ `);
19013
+ process.stderr.write(`${DIM} Hooks verify skills on every Claude Code session.${RESET}
19014
+
19015
+ `);
19016
+ const scope = await Jt({
19017
+ message: "Where should oathbound install hooks?",
19018
+ options: [
19019
+ { value: "both", label: "Global + this project", hint: "recommended" },
19020
+ { value: "global", label: "Global only", hint: "~/.claude/settings.json" },
19021
+ { value: "local", label: "This project only", hint: ".claude/settings.json" }
19022
+ ]
19023
+ });
19024
+ if (Ct(scope)) {
19025
+ Nt("Pull cancelled.");
19026
+ process.exit(1);
19027
+ }
19028
+ if (scope === "both" || scope === "global")
19029
+ initGlobal();
19030
+ if (scope === "both" || scope === "local")
19031
+ await initLocal();
19032
+ }
19033
+ async function pull(skillArg, options = {}) {
18550
19034
  const parsed = parseSkillArg(skillArg);
18551
19035
  if (!parsed)
18552
19036
  usage();
18553
19037
  const { namespace, name, version: version3 } = parsed;
18554
19038
  const fullName = `${namespace}/${name}`;
19039
+ await ensureInitialized();
18555
19040
  console.log(`
18556
19041
  ${BRAND} ${TEAL}↓ Pulling ${fullName}${version3 ? `@${version3}` : ""}...${RESET}`);
18557
19042
  const supabase = createClient(SUPABASE_URL2, SUPABASE_ANON_KEY2);
@@ -18574,7 +19059,7 @@ ${BRAND} ${TEAL}↓ Pulling ${fullName}${version3 ? `@${version3}` : ""}...${RES
18574
19059
  fail("Download failed", downloadError?.message ?? "Unknown storage error");
18575
19060
  }
18576
19061
  const buffer = Buffer.from(await blob.arrayBuffer());
18577
- const tarFile = import_node_path8.join(import_node_os4.tmpdir(), `oathbound-${name}-${Date.now()}.tar.gz`);
19062
+ const tarFile = import_node_path9.join(import_node_os4.tmpdir(), `oathbound-${name}-${Date.now()}.tar.gz`);
18578
19063
  const verifySpinner = spinner("Verifying...");
18579
19064
  const hash = import_node_crypto2.createHash("sha256").update(buffer).digest("hex");
18580
19065
  verifySpinner.stop();
@@ -18583,21 +19068,30 @@ ${BRAND} ${TEAL}↓ Pulling ${fullName}${version3 ? `@${version3}` : ""}...${RES
18583
19068
  console.log(`${RED} expected: ${skill.tar_hash}${RESET}`);
18584
19069
  fail("Verification failed", `Downloaded file does not match expected hash for ${fullName}`);
18585
19070
  }
18586
- let skillsDir = findSkillsDir();
18587
- if (!skillsDir.endsWith(".claude/skills") && !skillsDir.includes(".claude/skills")) {
18588
- skillsDir = import_node_path8.join(process.cwd(), ".claude", "skills");
18589
- import_node_fs8.mkdirSync(skillsDir, { recursive: true });
18590
- console.log(`${DIM} Created ${skillsDir}${RESET}`);
19071
+ let skillsDir;
19072
+ if (options.global) {
19073
+ skillsDir = import_node_path9.join(import_node_os4.homedir(), ".claude", "skills");
19074
+ import_node_fs9.mkdirSync(skillsDir, { recursive: true });
19075
+ } else {
19076
+ const dirs = findSkillsDirs();
19077
+ const localEntry = dirs.find((d) => d.source === "local");
19078
+ if (localEntry) {
19079
+ skillsDir = localEntry.path;
19080
+ } else {
19081
+ skillsDir = import_node_path9.join(process.cwd(), ".claude", "skills");
19082
+ import_node_fs9.mkdirSync(skillsDir, { recursive: true });
19083
+ console.log(`${DIM} Created ${skillsDir}${RESET}`);
19084
+ }
18591
19085
  }
18592
- import_node_fs8.writeFileSync(tarFile, buffer);
19086
+ import_node_fs9.writeFileSync(tarFile, buffer);
18593
19087
  try {
18594
- import_node_child_process2.execFileSync("tar", ["-xf", tarFile, "-C", skillsDir], { stdio: "pipe" });
19088
+ import_node_child_process3.execFileSync("tar", ["-xf", tarFile, "-C", skillsDir], { stdio: "pipe" });
18595
19089
  } catch (e) {
18596
- import_node_fs8.unlinkSync(tarFile);
19090
+ import_node_fs9.unlinkSync(tarFile);
18597
19091
  const msg = e instanceof Error ? e.message : "Unknown error";
18598
19092
  fail("Extraction failed", msg);
18599
19093
  }
18600
- import_node_fs8.unlinkSync(tarFile);
19094
+ import_node_fs9.unlinkSync(tarFile);
18601
19095
  try {
18602
19096
  const trackRes = await fetch(`${API_BASE6}/api/downloads`, {
18603
19097
  method: "POST",
@@ -18611,7 +19105,7 @@ ${BRAND} ${TEAL}↓ Pulling ${fullName}${version3 ? `@${version3}` : ""}...${RES
18611
19105
  } catch {}
18612
19106
  console.log(`${BOLD}${GREEN} ✓ Skill verified${RESET}`);
18613
19107
  console.log(`${DIM} ${fullName} v${skill.version}${RESET}`);
18614
- console.log(`${DIM} → ${import_node_path8.join(skillsDir, name)}${RESET}`);
19108
+ console.log(`${DIM} → ${import_node_path9.join(skillsDir, name)}${RESET}`);
18615
19109
  }
18616
19110
  async function agentPull(agentArg) {
18617
19111
  const parsed = parseSkillArg(agentArg);
@@ -18652,9 +19146,9 @@ ${BRAND} ${TEAL}↓ Pulling agent ${fullName}${version3 ? `@${version3}` : ""}..
18652
19146
  if (name.includes("/") || name.includes("\\") || name.includes("..")) {
18653
19147
  fail("Invalid agent name", `Name "${name}" contains path traversal characters`);
18654
19148
  }
18655
- const agentsDir = import_node_path8.join(process.cwd(), ".claude", "agents");
18656
- import_node_fs8.mkdirSync(agentsDir, { recursive: true });
18657
- const targetPath = import_node_path8.join(agentsDir, `${name}.md`);
19149
+ const agentsDir = import_node_path9.join(process.cwd(), ".claude", "agents");
19150
+ import_node_fs9.mkdirSync(agentsDir, { recursive: true });
19151
+ const targetPath = import_node_path9.join(agentsDir, `${name}.md`);
18658
19152
  if (!targetPath.startsWith(agentsDir)) {
18659
19153
  fail("Invalid agent name", `Resolved path escapes agents directory`);
18660
19154
  }
@@ -18682,7 +19176,7 @@ ${YELLOW}${BOLD} ⚠ This agent defines MCP servers (external connections):${RES
18682
19176
  fail("Aborted", "Agent not installed");
18683
19177
  }
18684
19178
  }
18685
- import_node_fs8.writeFileSync(targetPath, content);
19179
+ import_node_fs9.writeFileSync(targetPath, content);
18686
19180
  try {
18687
19181
  const trackRes = await fetch(`${API_BASE6}/api/downloads`, {
18688
19182
  method: "POST",
@@ -18737,7 +19231,11 @@ if (require.main == module) {
18737
19231
  }
18738
19232
  }
18739
19233
  if (subcommand === "init") {
18740
- await init().catch((err) => {
19234
+ const initArgs = args.slice(1);
19235
+ await init({
19236
+ global: initArgs.includes("--global"),
19237
+ local: initArgs.includes("--local")
19238
+ }).catch((err) => {
18741
19239
  const msg = err instanceof Error ? err.message : "Unknown error";
18742
19240
  fail("Init failed", msg);
18743
19241
  });
@@ -18745,7 +19243,7 @@ if (require.main == module) {
18745
19243
  setup();
18746
19244
  } else if (subcommand === "verify") {
18747
19245
  const isCheck = args.includes("--check");
18748
- const run = isCheck ? verifyCheck : () => verify(SUPABASE_URL2, SUPABASE_ANON_KEY2);
19246
+ const run = isCheck ? verifyCheck : () => verify(SUPABASE_URL2, SUPABASE_ANON_KEY2, VERSION);
18749
19247
  await run().catch((err) => {
18750
19248
  const msg = err instanceof Error ? err.message : "Unknown error";
18751
19249
  process.stderr.write(`oathbound verify: ${msg}
@@ -18788,11 +19286,13 @@ if (require.main == module) {
18788
19286
  });
18789
19287
  } else {
18790
19288
  const PULL_ALIASES = new Set(["pull", "i", "install"]);
18791
- const skillArg = args[1];
19289
+ const pullArgs = args.slice(1);
19290
+ const isGlobalPull = pullArgs.includes("--global");
19291
+ const skillArg = pullArgs.find((a) => !a.startsWith("--"));
18792
19292
  if (!subcommand || !PULL_ALIASES.has(subcommand) || !skillArg) {
18793
19293
  usage();
18794
19294
  }
18795
- await pull(skillArg).catch((err) => {
19295
+ await pull(skillArg, { global: isGlobalPull }).catch((err) => {
18796
19296
  const msg = err instanceof Error ? err.message : "Unknown error";
18797
19297
  fail("Unexpected error", msg);
18798
19298
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oathbound",
3
- "version": "0.15.1",
3
+ "version": "0.17.0",
4
4
  "description": "Install verified Claude Code skills and agents from the Oath Bound registry",
5
5
  "license": "MIT",
6
6
  "author": "Josh Anderson",