@hasna/skills 0.10.27 → 0.10.30

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/sdk/index.js CHANGED
@@ -8209,7 +8209,7 @@ var require_client = __commonJS((exports) => {
8209
8209
  };
8210
8210
  };
8211
8211
  var sleep = (seconds) => {
8212
- return new Promise((resolve19) => setTimeout(resolve19, seconds * 1000));
8212
+ return new Promise((resolve20) => setTimeout(resolve20, seconds * 1000));
8213
8213
  };
8214
8214
  var waiterServiceDefaults = {
8215
8215
  minDelay: 2,
@@ -8338,8 +8338,8 @@ var require_client = __commonJS((exports) => {
8338
8338
  };
8339
8339
  var abortTimeout = (abortSignal) => {
8340
8340
  let onAbort;
8341
- const promise = new Promise((resolve19) => {
8342
- onAbort = () => resolve19({ state: WaiterState.ABORTED });
8341
+ const promise = new Promise((resolve20) => {
8342
+ onAbort = () => resolve20({ state: WaiterState.ABORTED });
8343
8343
  if (typeof abortSignal.addEventListener === "function") {
8344
8344
  abortSignal.addEventListener("abort", onAbort);
8345
8345
  } else {
@@ -9477,7 +9477,7 @@ var require_config = __commonJS((exports) => {
9477
9477
  };
9478
9478
  var imdsRequest = async (options) => {
9479
9479
  const { request: request2 } = __require("http");
9480
- return new Promise((resolve19, reject) => {
9480
+ return new Promise((resolve20, reject) => {
9481
9481
  const req = request2({
9482
9482
  hostname: options.hostname,
9483
9483
  port: options.port,
@@ -9505,7 +9505,7 @@ var require_config = __commonJS((exports) => {
9505
9505
  const chunks = [];
9506
9506
  res.on("data", (chunk) => chunks.push(chunk));
9507
9507
  res.on("end", () => {
9508
- resolve19(Buffer.concat(chunks));
9508
+ resolve20(Buffer.concat(chunks));
9509
9509
  req.destroy();
9510
9510
  });
9511
9511
  });
@@ -10514,7 +10514,7 @@ var require_serde = __commonJS((exports) => {
10514
10514
  var { createHmac: createHmac2, createHash: createHash21, getRandomValues } = __require("crypto");
10515
10515
  var { hasOwn: hasOwn2, HttpResponse } = require_transport();
10516
10516
  exports.hasOwn = hasOwn2;
10517
- var { ReadStream, lstatSync: lstatSync23, fstatSync: fstatSync4 } = __require("fs");
10517
+ var { ReadStream, lstatSync: lstatSync24, fstatSync: fstatSync4 } = __require("fs");
10518
10518
  var { toEndpointV1 } = require_endpoints();
10519
10519
  var { Readable, Writable, PassThrough } = __require("stream");
10520
10520
  var isArrayBuffer = (arg) => typeof ArrayBuffer === "function" && arg instanceof ArrayBuffer || Object.prototype.toString.call(arg) === "[object ArrayBuffer]";
@@ -11280,7 +11280,7 @@ var require_serde = __commonJS((exports) => {
11280
11280
  return body.end + 1 - body.start;
11281
11281
  } else if (body instanceof ReadStream) {
11282
11282
  if (body.path != null) {
11283
- return lstatSync23(body.path).size;
11283
+ return lstatSync24(body.path).size;
11284
11284
  } else if (typeof body.fd === "number") {
11285
11285
  return fstatSync4(body.fd).size;
11286
11286
  }
@@ -11861,7 +11861,7 @@ ${value}\r
11861
11861
  if (isReadableStream(stream)) {
11862
11862
  return headStream$1(stream, bytes);
11863
11863
  }
11864
- return new Promise((resolve19, reject) => {
11864
+ return new Promise((resolve20, reject) => {
11865
11865
  const collector = new Collector$1;
11866
11866
  collector.limit = bytes;
11867
11867
  stream.pipe(collector);
@@ -11872,7 +11872,7 @@ ${value}\r
11872
11872
  collector.on("error", reject);
11873
11873
  collector.on("finish", function() {
11874
11874
  const bytes2 = concatBytes(this.buffers);
11875
- resolve19(bytes2);
11875
+ resolve20(bytes2);
11876
11876
  });
11877
11877
  });
11878
11878
  };
@@ -11986,7 +11986,7 @@ ${value}\r
11986
11986
  if (isReadableStream(stream)) {
11987
11987
  return collectReadableStream(stream);
11988
11988
  }
11989
- return new Promise((resolve19, reject) => {
11989
+ return new Promise((resolve20, reject) => {
11990
11990
  const collector = new Collector;
11991
11991
  const nodeStream = stream;
11992
11992
  nodeStream.pipe(collector);
@@ -11997,7 +11997,7 @@ ${value}\r
11997
11997
  collector.on("error", reject);
11998
11998
  collector.on("finish", function() {
11999
11999
  const bytes = concatBytes(this.bufferedBytes);
12000
- resolve19(bytes);
12000
+ resolve20(bytes);
12001
12001
  });
12002
12002
  });
12003
12003
  };
@@ -12189,7 +12189,7 @@ var require_checksum = __commonJS((exports) => {
12189
12189
  callback();
12190
12190
  }
12191
12191
  }
12192
- var fileStreamHasher = (hashCtor, fileStream) => new Promise((resolve19, reject) => {
12192
+ var fileStreamHasher = (hashCtor, fileStream) => new Promise((resolve20, reject) => {
12193
12193
  if (!isReadStream(fileStream)) {
12194
12194
  reject(new Error("Unable to calculate hash for non-file streams."));
12195
12195
  return;
@@ -12207,7 +12207,7 @@ var require_checksum = __commonJS((exports) => {
12207
12207
  });
12208
12208
  hashCalculator.on("error", reject);
12209
12209
  hashCalculator.on("finish", function() {
12210
- hash2.digest().then(resolve19).catch(reject);
12210
+ hash2.digest().then(resolve20).catch(reject);
12211
12211
  });
12212
12212
  });
12213
12213
  var isReadStream = (stream) => typeof stream.path === "string";
@@ -12218,14 +12218,14 @@ var require_checksum = __commonJS((exports) => {
12218
12218
  const hash2 = new hashCtor;
12219
12219
  const hashCalculator = new HashCalculator(hash2);
12220
12220
  readableStream.pipe(hashCalculator);
12221
- return new Promise((resolve19, reject) => {
12221
+ return new Promise((resolve20, reject) => {
12222
12222
  readableStream.on("error", (err) => {
12223
12223
  hashCalculator.end();
12224
12224
  reject(err);
12225
12225
  });
12226
12226
  hashCalculator.on("error", reject);
12227
12227
  hashCalculator.on("finish", () => {
12228
- hash2.digest().then(resolve19).catch(reject);
12228
+ hash2.digest().then(resolve20).catch(reject);
12229
12229
  });
12230
12230
  });
12231
12231
  };
@@ -13334,7 +13334,7 @@ var require_event_streams = __commonJS((exports) => {
13334
13334
  streamEnded = true;
13335
13335
  });
13336
13336
  while (!generationEnded) {
13337
- const value = await new Promise((resolve19) => setTimeout(() => resolve19(records.shift()), 0));
13337
+ const value = await new Promise((resolve20) => setTimeout(() => resolve20(records.shift()), 0));
13338
13338
  if (value) {
13339
13339
  yield value;
13340
13340
  }
@@ -14852,7 +14852,7 @@ var require_retry = __commonJS((exports) => {
14852
14852
  }
14853
14853
  };
14854
14854
  }
14855
- var cooldown = (ms) => new Promise((resolve19) => setTimeout(resolve19, ms));
14855
+ var cooldown = (ms) => new Promise((resolve20) => setTimeout(resolve20, ms));
14856
14856
  var isRetryStrategyV2 = (retryStrategy) => typeof retryStrategy.acquireInitialRetryToken !== "undefined" && typeof retryStrategy.refreshRetryTokenForRetry !== "undefined" && typeof retryStrategy.recordSuccess !== "undefined";
14857
14857
  var getRetryErrorInfo = (error, logger) => {
14858
14858
  const errorInfo = {
@@ -14951,7 +14951,7 @@ var require_retry = __commonJS((exports) => {
14951
14951
  this.refillTokenBucket();
14952
14952
  while (amount > this.availableTokens) {
14953
14953
  const delay = (amount - this.availableTokens) / this.fillRate * 1000;
14954
- await new Promise((resolve19) => DefaultRateLimiter.setTimeoutFn(resolve19, delay));
14954
+ await new Promise((resolve20) => DefaultRateLimiter.setTimeoutFn(resolve20, delay));
14955
14955
  this.refillTokenBucket();
14956
14956
  }
14957
14957
  this.availableTokens = this.availableTokens - amount;
@@ -15293,7 +15293,7 @@ var require_retry = __commonJS((exports) => {
15293
15293
  const delayFromResponse = getDelayFromRetryAfterHeader(err.$response);
15294
15294
  const delay = Math.max(delayFromResponse || 0, delayFromDecider);
15295
15295
  totalDelay += delay;
15296
- await new Promise((resolve19) => setTimeout(resolve19, delay));
15296
+ await new Promise((resolve20) => setTimeout(resolve20, delay));
15297
15297
  continue;
15298
15298
  }
15299
15299
  if (!err.$metadata) {
@@ -24646,7 +24646,7 @@ var init_node_http = () => {};
24646
24646
 
24647
24647
  // node_modules/@smithy/credential-provider-imds/dist-es/remoteProvider/httpRequest.js
24648
24648
  function httpRequest(options) {
24649
- return new Promise((resolve19, reject) => {
24649
+ return new Promise((resolve20, reject) => {
24650
24650
  const req = node_http.request({
24651
24651
  method: "GET",
24652
24652
  ...options,
@@ -24671,7 +24671,7 @@ function httpRequest(options) {
24671
24671
  chunks.push(chunk);
24672
24672
  });
24673
24673
  res.on("end", () => {
24674
- resolve19(Buffer.concat(chunks));
24674
+ resolve20(Buffer.concat(chunks));
24675
24675
  req.destroy();
24676
24676
  });
24677
24677
  });
@@ -25168,21 +25168,21 @@ var require_dist_cjs6 = __commonJS((exports) => {
25168
25168
  let sendBody = true;
25169
25169
  if (!externalAgent && expect === "100-continue") {
25170
25170
  sendBody = await Promise.race([
25171
- new Promise((resolve19) => {
25172
- timeoutId = Number(timing.setTimeout(() => resolve19(true), Math.max(MIN_WAIT_TIME, maxContinueTimeoutMs)));
25171
+ new Promise((resolve20) => {
25172
+ timeoutId = Number(timing.setTimeout(() => resolve20(true), Math.max(MIN_WAIT_TIME, maxContinueTimeoutMs)));
25173
25173
  }),
25174
- new Promise((resolve19) => {
25174
+ new Promise((resolve20) => {
25175
25175
  httpRequest2.on("continue", () => {
25176
25176
  timing.clearTimeout(timeoutId);
25177
- resolve19(true);
25177
+ resolve20(true);
25178
25178
  });
25179
25179
  httpRequest2.on("response", () => {
25180
25180
  timing.clearTimeout(timeoutId);
25181
- resolve19(false);
25181
+ resolve20(false);
25182
25182
  });
25183
25183
  httpRequest2.on("error", () => {
25184
25184
  timing.clearTimeout(timeoutId);
25185
- resolve19(false);
25185
+ resolve20(false);
25186
25186
  });
25187
25187
  })
25188
25188
  ]);
@@ -25259,13 +25259,13 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
25259
25259
  return socketWarningTimestamp;
25260
25260
  }
25261
25261
  constructor(options) {
25262
- this.configProvider = new Promise((resolve19, reject) => {
25262
+ this.configProvider = new Promise((resolve20, reject) => {
25263
25263
  if (typeof options === "function") {
25264
25264
  options().then((_options) => {
25265
- resolve19(this.resolveDefaultConfig(_options));
25265
+ resolve20(this.resolveDefaultConfig(_options));
25266
25266
  }).catch(reject);
25267
25267
  } else {
25268
- resolve19(this.resolveDefaultConfig(options));
25268
+ resolve20(this.resolveDefaultConfig(options));
25269
25269
  }
25270
25270
  });
25271
25271
  }
@@ -25297,7 +25297,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
25297
25297
  timing.clearTimeout(socketTimeoutId);
25298
25298
  timing.clearTimeout(keepAliveTimeoutId);
25299
25299
  };
25300
- const resolve19 = async (arg) => {
25300
+ const resolve20 = async (arg) => {
25301
25301
  await writeRequestBodyPromise;
25302
25302
  clearTimeouts();
25303
25303
  _resolve(arg);
@@ -25361,7 +25361,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
25361
25361
  headers: getTransformedHeaders(res.headers),
25362
25362
  body: res
25363
25363
  });
25364
- resolve19({ response: httpResponse });
25364
+ resolve20({ response: httpResponse });
25365
25365
  });
25366
25366
  req.on("error", (err) => {
25367
25367
  if (NODEJS_TIMEOUT_ERROR_CODES.includes(err.code)) {
@@ -25693,13 +25693,13 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
25693
25693
  return new NodeHttp2Handler(instanceOrOptions);
25694
25694
  }
25695
25695
  constructor(options) {
25696
- this.configProvider = new Promise((resolve19, reject) => {
25696
+ this.configProvider = new Promise((resolve20, reject) => {
25697
25697
  if (typeof options === "function") {
25698
25698
  options().then((opts) => {
25699
- resolve19(opts || {});
25699
+ resolve20(opts || {});
25700
25700
  }).catch(reject);
25701
25701
  } else {
25702
- resolve19(options || {});
25702
+ resolve20(options || {});
25703
25703
  }
25704
25704
  });
25705
25705
  }
@@ -25724,7 +25724,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
25724
25724
  return new Promise((_resolve, _reject) => {
25725
25725
  let fulfilled = false;
25726
25726
  let writeRequestBodyPromise = undefined;
25727
- const resolve19 = async (arg) => {
25727
+ const resolve20 = async (arg) => {
25728
25728
  await writeRequestBodyPromise;
25729
25729
  _resolve(arg);
25730
25730
  };
@@ -25809,7 +25809,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
25809
25809
  body: clientHttp2Stream
25810
25810
  });
25811
25811
  fulfilled = true;
25812
- resolve19({ response: httpResponse });
25812
+ resolve20({ response: httpResponse });
25813
25813
  if (useIsolatedSession) {
25814
25814
  session.close();
25815
25815
  clientHttp2Stream.on("end", () => {
@@ -25942,7 +25942,7 @@ var retryWrapper = (toRetry, maxRetries, delayMs) => {
25942
25942
  try {
25943
25943
  return await toRetry();
25944
25944
  } catch (e3) {
25945
- await new Promise((resolve19) => setTimeout(resolve19, delayMs));
25945
+ await new Promise((resolve20) => setTimeout(resolve20, delayMs));
25946
25946
  }
25947
25947
  }
25948
25948
  return await toRetry();
@@ -29446,7 +29446,7 @@ var require_signin = __commonJS((exports) => {
29446
29446
  import { createHash as createHash21, createPrivateKey, createPublicKey, sign } from "crypto";
29447
29447
  import { promises as fs2 } from "fs";
29448
29448
  import { homedir as homedir7 } from "os";
29449
- import { dirname as dirname21, join as join33 } from "path";
29449
+ import { dirname as dirname21, join as join34 } from "path";
29450
29450
  var import_config28, import_protocols3, LoginCredentialsFetcher;
29451
29451
  var init_LoginCredentialsFetcher = __esm(() => {
29452
29452
  import_config28 = __toESM(require_config(), 1);
@@ -29613,10 +29613,10 @@ var init_LoginCredentialsFetcher = __esm(() => {
29613
29613
  await fs2.writeFile(tokenFilePath, JSON.stringify(token, null, 2), "utf8");
29614
29614
  }
29615
29615
  getTokenFilePath() {
29616
- const directory = process.env.AWS_LOGIN_CACHE_DIRECTORY ?? join33(homedir7(), ".aws", "login", "cache");
29616
+ const directory = process.env.AWS_LOGIN_CACHE_DIRECTORY ?? join34(homedir7(), ".aws", "login", "cache");
29617
29617
  const loginSessionBytes = Buffer.from(this.loginSession, "utf8");
29618
29618
  const loginSessionSha256 = createHash21("sha256").update(loginSessionBytes).digest("hex");
29619
- return join33(directory, `${loginSessionSha256}.json`);
29619
+ return join34(directory, `${loginSessionSha256}.json`);
29620
29620
  }
29621
29621
  derToRawSignature(derSignature) {
29622
29622
  let offset = 2;
@@ -31065,9 +31065,9 @@ import { chmod, mkdir, readFile, rename, writeFile as writeFile2 } from "fs/prom
31065
31065
  import { Buffer as Buffer2 } from "buffer";
31066
31066
  import { existsSync as existsSync22 } from "fs";
31067
31067
  import { join as join210 } from "path";
31068
- import { existsSync as existsSync16 } from "fs";
31068
+ import { existsSync as existsSync17 } from "fs";
31069
31069
  import { homedir as homedir8 } from "os";
31070
- import { join as join37, resolve as resolve19 } from "path";
31070
+ import { join as join38, resolve as resolve20 } from "path";
31071
31071
  import { homedir as pathsResolverHomedir2 } from "os";
31072
31072
  import { join as pathsResolverJoin2 } from "path";
31073
31073
  import { createHmac as createHmac4, timingSafeEqual as timingSafeEqual3 } from "crypto";
@@ -31228,7 +31228,7 @@ function effectiveHome2() {
31228
31228
  return process.env["HOME"] || process.env["USERPROFILE"] || homedir8();
31229
31229
  }
31230
31230
  function legacyHomeDir() {
31231
- return join37(effectiveHome2(), ".hasna", "events");
31231
+ return join38(effectiveHome2(), ".hasna", "events");
31232
31232
  }
31233
31233
  function resolverHome() {
31234
31234
  return dataDir2({ app: "events", home: effectiveHome2() || undefined });
@@ -31237,7 +31237,7 @@ function adoptResolverHome(resolved, env = process.env) {
31237
31237
  const dataOverride = env.HASNA_DATA_HOME;
31238
31238
  if (typeof dataOverride === "string" && dataOverride.trim().length > 0)
31239
31239
  return true;
31240
- return existsSync16(join37(resolved, EVENTS_STORE_SENTINEL_FILE));
31240
+ return existsSync17(join38(resolved, EVENTS_STORE_SENTINEL_FILE));
31241
31241
  }
31242
31242
  function exactEventsHome() {
31243
31243
  const dir = process.env[HASNA_EVENTS_DIR_ENV];
@@ -31251,9 +31251,9 @@ function exactEventsHome() {
31251
31251
  function getEventsHome() {
31252
31252
  const exact = exactEventsHome();
31253
31253
  if (exact)
31254
- return resolve19(exact);
31254
+ return resolve20(exact);
31255
31255
  const resolved = resolverHome();
31256
- return adoptResolverHome(resolved) ? resolve19(resolved) : resolve19(legacyHomeDir());
31256
+ return adoptResolverHome(resolved) ? resolve20(resolved) : resolve20(legacyHomeDir());
31257
31257
  }
31258
31258
  function getEventsDataDir(override) {
31259
31259
  return override || getEventsHome();
@@ -32373,7 +32373,7 @@ var init_event_sink = __esm(() => {
32373
32373
  // package.json
32374
32374
  var package_default = {
32375
32375
  name: "@hasna/skills",
32376
- version: "0.10.27",
32376
+ version: "0.10.30",
32377
32377
  description: "Skills library for AI coding agents",
32378
32378
  type: "module",
32379
32379
  bin: {
@@ -37457,8 +37457,8 @@ async function reconcileSkillSession(input, options = {}) {
37457
37457
  // src/lib/selected-run.ts
37458
37458
  import { createHash as createHash20 } from "crypto";
37459
37459
  import { spawn as spawn2 } from "child_process";
37460
- import { mkdirSync as mkdirSync10, mkdtempSync as mkdtempSync3, writeFileSync as writeFileSync9, realpathSync as realpathSync11 } from "fs";
37461
- import { dirname as dirname20, join as join32, resolve as resolve18 } from "path";
37460
+ import { mkdirSync as mkdirSync10, mkdtempSync as mkdtempSync3, writeFileSync as writeFileSync9, realpathSync as realpathSync12 } from "fs";
37461
+ import { dirname as dirname20, join as join33, resolve as resolve19 } from "path";
37462
37462
  import { tmpdir, hostname as stationHostname2 } from "os";
37463
37463
 
37464
37464
  // src/lib/dependency-preparation.ts
@@ -37669,19 +37669,19 @@ async function prepareSkillDependencies(skillPath, env, timeoutMs = DEFAULT_PREP
37669
37669
  }
37670
37670
 
37671
37671
  // src/lib/skillinfo.ts
37672
- import { existsSync as existsSync14, readFileSync as readFileSync21 } from "fs";
37673
- import { join as join31 } from "path";
37672
+ import { existsSync as existsSync15, readFileSync as readFileSync21 } from "fs";
37673
+ import { join as join32 } from "path";
37674
37674
 
37675
37675
  // src/lib/installer.ts
37676
- import { existsSync as existsSync13, readFileSync as readFileSync20, rmSync as rmSync4 } from "fs";
37677
- import { join as join30 } from "path";
37676
+ import { existsSync as existsSync14, readFileSync as readFileSync20, rmSync as rmSync4 } from "fs";
37677
+ import { join as join31 } from "path";
37678
37678
  import { homedir as homedir6 } from "os";
37679
37679
 
37680
37680
  // src/lib/agent-sync.ts
37681
37681
  import {
37682
37682
  cpSync as cpSync2,
37683
- existsSync as existsSync10,
37684
- lstatSync as lstatSync22,
37683
+ existsSync as existsSync11,
37684
+ lstatSync as lstatSync23,
37685
37685
  mkdirSync as mkdirSync8,
37686
37686
  mkdtempSync as mkdtempSync2,
37687
37687
  readFileSync as readFileSync17,
@@ -37692,7 +37692,7 @@ import {
37692
37692
  writeFileSync as writeFileSync7
37693
37693
  } from "fs";
37694
37694
  import { homedir as homedir5 } from "os";
37695
- import { basename as basename11, dirname as dirname19, join as join27 } from "path";
37695
+ import { basename as basename11, dirname as dirname19, join as join28 } from "path";
37696
37696
 
37697
37697
  // src/lib/codex-local-mcp-controls.ts
37698
37698
  function isCodexLocalStdioMcpServer(name, server) {
@@ -38995,12 +38995,14 @@ function disablesOneSkill(entry) {
38995
38995
  return selector.length === 1 && typeof entry[selector[0]] === "string" && entry[selector[0]].length > 0;
38996
38996
  }
38997
38997
  function inference(target, version) {
38998
- const keys2 = version === 3 ? [...INFERENCE, "service_tier", "plan_mode_reasoning_effort"] : INFERENCE;
38998
+ const keys2 = version === 3 ? [...INFERENCE, "service_tier", "plan_mode_reasoning_effort", "personality"] : INFERENCE;
38999
38999
  for (const key of keys2)
39000
39000
  if (Object.hasOwn(target, key)) {
39001
39001
  const value = target[key];
39002
39002
  if (key === "model")
39003
39003
  need3(typeof value === "string" && MODEL.test(value));
39004
+ else if (key === "personality")
39005
+ need3(typeof value === "string" && ["none", "friendly", "pragmatic"].includes(value));
39004
39006
  else if (version === 3 && key !== "model_verbosity") {
39005
39007
  need3(typeof value === "string" && value.length <= 128 && !/[\x00-\x1f\x7f]/.test(value));
39006
39008
  if (key !== "service_tier")
@@ -39070,6 +39072,8 @@ var NATIVE_SKILL_ROOTS = [
39070
39072
  ["codex", ".codex/skills"],
39071
39073
  ["codex", ".agents/skills"],
39072
39074
  ["gemini", ".gemini/skills"],
39075
+ ["sumi", ".sumi/skills"],
39076
+ ["sumi", ".sumi/skill"],
39073
39077
  ["codewith", ".codewith/skills"],
39074
39078
  ["opencode", ".config/opencode/skills"],
39075
39079
  ["opencode", ".opencode/skills"],
@@ -39086,8 +39090,8 @@ var NATIVE_SKILL_ROOTS = [
39086
39090
  // src/lib/agent-integration.ts
39087
39091
  import { createHash as createHash18, randomUUID as randomUUID3 } from "crypto";
39088
39092
  import { isDeepStrictEqual as isDeepStrictEqual6 } from "util";
39089
- import { existsSync as existsSync6, lstatSync as lstatSync19, statSync as statSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync14, readdirSync as readdirSync8, opendirSync as opendirSync5, readlinkSync as readlinkSync4, realpathSync as realpathSync7, renameSync as renameSync3, rmdirSync as rmdirSync3, writeFileSync as writeFileSync4, unlinkSync as unlinkSync4, chmodSync, openSync as openSync16, closeSync as closeSync16, fsyncSync as fsyncSync4, fstatSync as fstatSync16, readSync as readSync11, constants as constants12, linkSync as linkSync2 } from "fs";
39090
- import { dirname as dirname15, join as join22, resolve as resolve15, relative as relative4, isAbsolute as isAbsolute17, sep as sep5 } from "path";
39093
+ import { existsSync as existsSync7, lstatSync as lstatSync20, statSync as statSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync14, readdirSync as readdirSync8, opendirSync as opendirSync5, readlinkSync as readlinkSync4, realpathSync as realpathSync8, renameSync as renameSync3, rmdirSync as rmdirSync3, writeFileSync as writeFileSync4, unlinkSync as unlinkSync4, chmodSync, openSync as openSync16, closeSync as closeSync16, fsyncSync as fsyncSync4, fstatSync as fstatSync16, readSync as readSync11, constants as constants12, linkSync as linkSync2 } from "fs";
39094
+ import { dirname as dirname15, join as join23, resolve as resolve16, relative as relative4, isAbsolute as isAbsolute17, sep as sep5 } from "path";
39091
39095
  import { homedir as homedir3 } from "os";
39092
39096
 
39093
39097
  // src/lib/managed-policy.ts
@@ -39366,8 +39370,8 @@ function isOwnedCliBridge(path, expectedPaths) {
39366
39370
 
39367
39371
  // src/lib/agent-discovery.ts
39368
39372
  import { createHash as createHash17 } from "crypto";
39369
- import { lstatSync as lstatSync18, readFileSync as readFileSync13, readdirSync as readdirSync7, realpathSync as realpathSync6 } from "fs";
39370
- import { basename as basename7, dirname as dirname14, isAbsolute as isAbsolute16, join as join21, resolve as resolve14, sep as sep4 } from "path";
39373
+ import { lstatSync as lstatSync19, readFileSync as readFileSync13, readdirSync as readdirSync7, realpathSync as realpathSync7 } from "fs";
39374
+ import { basename as basename7, dirname as dirname14, isAbsolute as isAbsolute16, join as join22, resolve as resolve15, sep as sep4 } from "path";
39371
39375
  import { isDeepStrictEqual as isDeepStrictEqual4 } from "util";
39372
39376
 
39373
39377
  // node_modules/yaml/dist/index.js
@@ -41678,6 +41682,114 @@ function verifiesCodexHookDiscoverySource(binding, source, currentDigest, witnes
41678
41682
  return true;
41679
41683
  }
41680
41684
 
41685
+ // src/lib/agent-sumi.ts
41686
+ import { existsSync as existsSync6, lstatSync as lstatSync18, realpathSync as realpathSync6 } from "fs";
41687
+ import { join as join21, resolve as resolve14 } from "path";
41688
+ function sumiConfigDirectory(home, env = process.env) {
41689
+ for (const key of ["SUMI_CONFIG", "SUMI_CONFIG_CONTENT"])
41690
+ if (env[key] !== undefined)
41691
+ throw new Error(`Sumi ${key} requires a dedicated discovery adapter; unset it before Skills integration`);
41692
+ const selected = (key) => env[key]?.trim() ? env[key] : undefined;
41693
+ const expand = (value) => resolve14(value === "~" ? home : value.startsWith("~/") ? join21(home, value.slice(2)) : value);
41694
+ const explicit = selected("SUMI_CONFIG_DIR");
41695
+ const xdg = selected("XDG_CONFIG_HOME");
41696
+ const custom = selected("SUMI_HOME");
41697
+ const canonical6 = explicit ? expand(explicit) : xdg ? join21(expand(xdg), "sumi") : join21(custom ? expand(custom) : join21(home, ".hasna-internal/sumi"), "config");
41698
+ if (explicit || xdg || custom)
41699
+ return canonical6;
41700
+ const legacy = join21(home, ".config/sumi");
41701
+ const a = lstatSync18(canonical6, { throwIfNoEntry: false }), b = lstatSync18(legacy, { throwIfNoEntry: false });
41702
+ if (a && b && realpathSync6(canonical6) !== realpathSync6(legacy))
41703
+ throw new Error("Sumi config roots conflict; complete native home adoption before Skills integration");
41704
+ const path = a ? canonical6 : b ? legacy : canonical6;
41705
+ if (!existsSync6(path))
41706
+ return path;
41707
+ const physical = realpathSync6(path);
41708
+ if ((a?.isSymbolicLink() || b?.isSymbolicLink()) && ![canonical6, legacy].includes(physical))
41709
+ throw new Error("Sumi config alias must resolve to its canonical or legacy root");
41710
+ return physical;
41711
+ }
41712
+ function sumiBridgeRoot(home) {
41713
+ return join21(sumiConfigDirectory(home), "skills");
41714
+ }
41715
+ function sumiConfigPath(home) {
41716
+ return join21(sumiConfigDirectory(home), "sumi.json");
41717
+ }
41718
+ function renderSumiPlugin(command, profile) {
41719
+ return `// Managed by @hasna/skills. Regenerate with skills hook install --agent sumi.
41720
+ import { spawn } from "node:child_process";
41721
+ const command = ${JSON.stringify(command)};
41722
+ const profile = ${JSON.stringify(profile)};
41723
+ function context(input) {
41724
+ return new Promise((resolve, reject) => {
41725
+ const child = spawn(command, ["hook", "user-prompt", "--agent", "sumi", "--selection-profile", profile], { cwd: input.cwd, stdio: ["pipe", "pipe", "pipe"] });
41726
+ const chunks = []; let bytes = 0, failure;
41727
+ const timer = setTimeout(() => { failure = new Error("Skills prompt hook timed out"); child.kill("SIGKILL"); }, 15000);
41728
+ child.stdout.on("data", chunk => { bytes += chunk.length; if (bytes > 1048576) { failure = new Error("Skills prompt hook output exceeded its limit"); child.kill("SIGKILL"); } else chunks.push(chunk); });
41729
+ child.stderr.on("data", () => {});
41730
+ child.stdin.on("error", () => {});
41731
+ child.on("error", error => { clearTimeout(timer); reject(error); });
41732
+ child.on("close", code => {
41733
+ clearTimeout(timer);
41734
+ if (failure || code !== 0) return reject(failure ?? new Error("Skills prompt hook failed"));
41735
+ try {
41736
+ const result = JSON.parse(Buffer.concat(chunks).toString("utf8"));
41737
+ if (!result || typeof result !== "object" || Array.isArray(result)) throw new Error("Invalid Skills hook response");
41738
+ if (result.decision === "block" || result.continue === false) throw new Error("Skills prompt hook refused");
41739
+ if (Object.keys(result).length && (!result.hookSpecificOutput || result.hookSpecificOutput.hookEventName !== input.hook_event_name)) throw new Error("Invalid Skills hook response");
41740
+ const text = result.hookSpecificOutput?.additionalContext ?? "";
41741
+ if (typeof text !== "string") throw new Error("Invalid Skills prompt context");
41742
+ resolve(text);
41743
+ } catch (error) { reject(error); }
41744
+ });
41745
+ child.stdin.end(JSON.stringify(input));
41746
+ });
41747
+ }
41748
+ export default {
41749
+ id: "local.hasna-skills-cli",
41750
+ async setup(ctx) {
41751
+ if (!ctx?.session?.hook || !ctx?.session?.get || !ctx?.skill?.transform || !ctx?.tool?.hook) throw new Error("Unsupported Sumi native Skills contract");
41752
+ const registrations = [];
41753
+ const sessions = new Set();
41754
+ async function input(sessionID, prompt, first) {
41755
+ // The Promise adapter unwraps single-data endpoint responses.
41756
+ const session = await ctx.session.get({ sessionID });
41757
+ if (!session || session.id !== sessionID || typeof session.location?.directory !== "string" || (session.parentID !== undefined && typeof session.parentID !== "string") || session.parentID === sessionID) throw new Error("Invalid Sumi session custody");
41758
+ return { hook_event_name: first ? session.parentID ? "SubagentStart" : "SessionStart" : "UserPromptSubmit", cwd: session.location.directory, session_id: sessionID, parent_session_id: session.parentID ?? null, prompt, restore: true };
41759
+ }
41760
+ registrations.push(await ctx.skill.transform(editor => {
41761
+ for (const skill of editor.list()) if (skill.id !== "skills-cli" || skill.name !== "skills-cli") editor.remove(skill.id);
41762
+ }));
41763
+ // Native config transforms may add skills after this transform. Guard
41764
+ // both direct tool calls and prompt attachments at the consumption edge.
41765
+ registrations.push(await ctx.tool.hook("execute.before", event => {
41766
+ if (event.tool === "skill" && event.input?.id !== "skills-cli") throw new Error("Native Sumi skill payload refused; use Skills CLI");
41767
+ }));
41768
+ registrations.push(await ctx.session.hook("prompt", async event => {
41769
+ if (typeof event.prompt?.text !== "string") throw new Error("Invalid Sumi prompt");
41770
+ if (event.prompt.skills !== undefined && (!Array.isArray(event.prompt.skills) || event.prompt.skills.some(skill => skill?.id !== "skills-cli"))) throw new Error("Native Sumi skill attachment refused; use Skills CLI");
41771
+ await context(await input(event.sessionID, event.prompt.text, !sessions.has(event.sessionID)));
41772
+ sessions.add(event.sessionID);
41773
+ }));
41774
+ registrations.push(await ctx.session.hook("context", async event => {
41775
+ const last = event.messages.findLast(message => message.role === "user");
41776
+ const prompt = (last?.content ?? []).filter(part => part.type === "text").map(part => part.text).join("\\n");
41777
+ // Recheck on every primary request, including resumed and synthetic
41778
+ // sessions. The CLI owns optional failures versus explicit refusals.
41779
+ const text = await context(await input(event.sessionID, prompt, !sessions.has(event.sessionID)));
41780
+ if (text) event.system.push({ type: "text", text });
41781
+ sessions.add(event.sessionID);
41782
+ }));
41783
+ return async () => { for (const registration of registrations) await registration.dispose(); };
41784
+ },
41785
+ };
41786
+ `;
41787
+ }
41788
+ var SUMI_SKILL_PERMISSIONS = [
41789
+ { action: "skill", resource: "*", effect: "deny" },
41790
+ { action: "skill", resource: "skills-cli", effect: "allow" }
41791
+ ];
41792
+
41681
41793
  // src/lib/agent-discovery.ts
41682
41794
  var digest2 = (text2) => createHash17("sha256").update(text2).digest("hex");
41683
41795
  function parseConfig(text2, path, toml = false) {
@@ -41694,7 +41806,7 @@ function safe4(path) {
41694
41806
  if (!isAbsolute16(path) || path.includes("\x00"))
41695
41807
  throw new Error("Expected an absolute native discovery path");
41696
41808
  for (let cursor = path;; cursor = dirname14(cursor)) {
41697
- if (lstatSync18(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
41809
+ if (lstatSync19(cursor, { throwIfNoEntry: false })?.isSymbolicLink())
41698
41810
  throw new Error(`Refusing symlink native discovery input: ${cursor}`);
41699
41811
  if (dirname14(cursor) === cursor)
41700
41812
  break;
@@ -41704,7 +41816,7 @@ function read2(path, changes) {
41704
41816
  safe4(path);
41705
41817
  if (changes?.has(path))
41706
41818
  return changes.get(path);
41707
- const stat2 = lstatSync18(path, { throwIfNoEntry: false });
41819
+ const stat2 = lstatSync19(path, { throwIfNoEntry: false });
41708
41820
  if (!stat2)
41709
41821
  return null;
41710
41822
  if (!stat2.isFile() || stat2.size > 16 * 1024 * 1024)
@@ -41815,12 +41927,12 @@ function codexInstallationRoots(binding) {
41815
41927
  if (binding.agent !== "codex" || binding.method !== "reviewed" || proof.version !== "codex-cli 0.160.0" || !/^[a-f0-9]{64}$/.test(proof.catalogSha256) || !Array.isArray(proof.plugins) || !proof.plugins.length)
41816
41928
  throw new Error("Invalid native installation input proof");
41817
41929
  const cache = dirname14(dirname14(proof.plugins[0].pluginParent));
41818
- const config = join21(dirname14(dirname14(cache)), "config.toml"), home = dirname14(dirname14(dirname14(cache)));
41930
+ const config = join22(dirname14(dirname14(cache)), "config.toml"), home = dirname14(dirname14(dirname14(cache)));
41819
41931
  const configSource = binding.sources.find((source) => source.path === config && source.sha256 !== null && (!source.format || source.format === "toml" && source.fields?.includes("plugins")));
41820
- const nativeRoots = NATIVE_SKILL_ROOTS.filter(([agent]) => agent === "codex").map(([, path]) => join21(home, path));
41932
+ const nativeRoots = NATIVE_SKILL_ROOTS.filter(([agent]) => agent === "codex").map(([, path]) => join22(home, path));
41821
41933
  if (!configSource || proof.plugins.some((input) => nativeRoots.some((root2) => root2 === input.sourceRoot || root2.startsWith(input.sourceRoot + sep4) || input.sourceRoot.startsWith(root2 + sep4)) || binding.sources.some((source) => basename7(source.path) === "config.toml" && (source.path === input.sourceRoot || source.path.startsWith(input.sourceRoot + sep4)))))
41822
41934
  throw new Error("Native installation input overlaps configuration or loading roots");
41823
- if (proof.plugins.some((input) => dirname14(dirname14(input.pluginParent)) !== cache || !binding.sources.some((source) => source.path === join21(input.sourceRoot, ".codex-plugin/plugin.json") && source.sha256 !== null && source.format === undefined && source.fields === undefined)))
41935
+ if (proof.plugins.some((input) => dirname14(dirname14(input.pluginParent)) !== cache || !binding.sources.some((source) => source.path === join22(input.sourceRoot, ".codex-plugin/plugin.json") && source.sha256 !== null && source.format === undefined && source.fields === undefined)))
41824
41936
  throw new Error("Missing native installation input source witness");
41825
41937
  return reviewedCodexPluginSourceRoots(cache, proof.plugins, (path) => {
41826
41938
  const text2 = read2(path);
@@ -41862,19 +41974,19 @@ function captureDiscoveryPathSources(paths) {
41862
41974
  const budget = discoveryByteBudget();
41863
41975
  return paths.map((path) => ({ path, hashMode: "path-bytes", sha256: hashDiscoveryPathFile(path, budget) }));
41864
41976
  }
41865
- function assertProjectDiscovery(agent, directories, home, canonical6 = resolve14, reviewed) {
41977
+ function assertProjectDiscovery(agent, directories, home, canonical6 = resolve15, reviewed) {
41866
41978
  const homeConfigPath = canonical6(agentDiscoveryConfigPath(home, agent));
41867
41979
  for (const directory of directories) {
41868
- const isHome = resolve14(directory) === resolve14(home);
41980
+ const isHome = resolve15(directory) === resolve15(home);
41869
41981
  if (agent === "hermes") {
41870
41982
  assertHermesEnvironment(home);
41871
41983
  continue;
41872
41984
  }
41873
- if (isHome && agent !== "claude")
41985
+ if (isHome && agent !== "claude" && agent !== "sumi")
41874
41986
  continue;
41875
- const paths = agent === "claude" ? [...isHome ? [] : [".claude/settings.json"], ".claude/settings.local.json"] : agent === "codex" ? [".codex/config.toml"] : agent === "gemini" ? [".gemini/settings.json"] : agent === "opencode" ? ["opencode.json", "opencode.jsonc", ".opencode/opencode.json", ".opencode/opencode.jsonc"] : [".cursor/hooks.json"];
41987
+ const paths = agent === "claude" ? [...isHome ? [] : [".claude/settings.json"], ".claude/settings.local.json"] : agent === "codex" ? [".codex/config.toml"] : agent === "gemini" ? [".gemini/settings.json"] : agent === "opencode" ? ["opencode.json", "opencode.jsonc", ".opencode/opencode.json", ".opencode/opencode.jsonc"] : agent === "sumi" ? ["sumi.json", "sumi.jsonc", ".sumi/sumi.json", ".sumi/sumi.jsonc"] : [".cursor/hooks.json"];
41876
41988
  for (const suffix of paths) {
41877
- const path = canonical6(join21(directory, suffix)), raw = read2(path);
41989
+ const path = canonical6(join22(directory, suffix)), raw = read2(path);
41878
41990
  if (raw === null)
41879
41991
  continue;
41880
41992
  const isRootAliasedHomeConfig = agent === "claude" && suffix === ".claude/settings.json" || agent === "codex" && suffix === ".codex/config.toml";
@@ -41883,7 +41995,7 @@ function assertProjectDiscovery(agent, directories, home, canonical6 = resolve14
41883
41995
  if (suffix.endsWith(".jsonc"))
41884
41996
  throw new Error(`NATIVE_SKILL_DRIFT: project JSONC discovery configuration requires review: ${path}`);
41885
41997
  const config = parseConfig(raw, path, suffix.endsWith(".toml"));
41886
- const keys2 = agent === "claude" ? ["enabledPlugins", "extraKnownMarketplaces", "skillOverrides"] : agent === "codex" ? ["plugins", "marketplaces", "skills"] : agent === "gemini" ? ["skills", "extensions"] : agent === "opencode" ? ["plugin", "skills"] : ["hooks"];
41998
+ const keys2 = agent === "claude" ? ["enabledPlugins", "extraKnownMarketplaces", "skillOverrides"] : agent === "codex" ? ["plugins", "marketplaces", "skills"] : agent === "gemini" ? ["skills", "extensions"] : agent === "opencode" ? ["plugin", "skills"] : agent === "sumi" ? ["plugin", "plugins", "skills", "permissions"] : ["hooks"];
41887
41999
  let admittedPlugins = false;
41888
42000
  if (agent === "claude" && reviewed?.agent === agent && reviewed.method === "reviewed" && config.enabledPlugins && typeof config.enabledPlugins === "object" && !Array.isArray(config.enabledPlugins)) {
41889
42001
  const exact = reviewed.sources.find((source) => source.path === path && source.format === undefined && source.fields === undefined && (source.hashMode === undefined || source.hashMode === "bytes"));
@@ -41896,19 +42008,28 @@ function assertProjectDiscovery(agent, directories, home, canonical6 = resolve14
41896
42008
  if (keys2.some((key) => config[key] !== undefined && !(key === "enabledPlugins" && admittedPlugins)) || config.disableAllHooks === true || config.disableBundledSkills === false || config.hooksConfig?.enabled === false || config.permission?.skill !== undefined || config.permissions?.deny?.some((rule) => typeof rule === "string" && /^Skill(?:\(|$)/.test(rule)))
41897
42009
  throw new Error(`NATIVE_SKILL_DRIFT: higher-precedence project skill or hook configuration requires review: ${path}`);
41898
42010
  }
42011
+ if (agent === "sumi")
42012
+ for (const name of ["plugin", "plugins"]) {
42013
+ const path = canonical6(join22(directory, ".sumi", name));
42014
+ safe4(path);
42015
+ if (lstatSync19(path, { throwIfNoEntry: false })?.isDirectory() && readdirSync7(path).length)
42016
+ throw new Error(`NATIVE_SKILL_DRIFT: project Sumi plugins require a dedicated discovery review: ${path}`);
42017
+ }
41899
42018
  if (agent === "claude") {
41900
- const commands = canonical6(join21(directory, ".claude/commands"));
42019
+ const commands = canonical6(join22(directory, ".claude/commands"));
41901
42020
  safe4(commands);
41902
- if (lstatSync18(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync7(commands).length)
42021
+ if (lstatSync19(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync7(commands).length)
41903
42022
  throw new Error("NATIVE_SKILL_DRIFT: legacy project command discovery requires a dedicated format adapter");
41904
42023
  }
41905
42024
  }
41906
42025
  }
41907
42026
  function agentDiscoveryConfigPath(home, agent) {
41908
- return join21(home, agent === "hermes" ? ".hermes/config.yaml" : agent === "opencode" ? ".config/opencode/opencode.json" : `.${agent}/${agent === "codex" ? "config.toml" : agent === "cursor" ? "hooks.json" : "settings.json"}`);
42027
+ if (agent === "sumi")
42028
+ return sumiConfigPath(home);
42029
+ return join22(home, agent === "hermes" ? ".hermes/config.yaml" : agent === "opencode" ? ".config/opencode/opencode.json" : `.${agent}/${agent === "codex" ? "config.toml" : agent === "cursor" ? "hooks.json" : "settings.json"}`);
41909
42030
  }
41910
42031
  function resolveAgentDiscovery(options) {
41911
- const canonical6 = options.canonical ?? resolve14, home = resolve14(options.home), agent = options.agent;
42032
+ const canonical6 = options.canonical ?? resolve15, home = resolve15(options.home), agent = options.agent;
41912
42033
  const sources = [], roots = new Set, builtinNames = [];
41913
42034
  const witness = (path, format, fields2) => {
41914
42035
  const source = { path: canonical6(path), sha256: null, ...format ? { format, fields: fields2 } : {} };
@@ -41919,13 +42040,49 @@ function resolveAgentDiscovery(options) {
41919
42040
  if (agent === "hermes")
41920
42041
  assertHermesEnvironment(home);
41921
42042
  const configPath = agentDiscoveryConfigPath(home, agent);
41922
- const configText = witness(configPath, agent === "hermes" ? "yaml" : agent === "codex" ? "toml" : "json", agent === "hermes" ? ["skills", "plugins", "hooks"] : agent === "claude" ? ["enabledPlugins", "extraKnownMarketplaces"] : agent === "codex" ? [...CODEX_DISCOVERY_PROJECTION_FIELDS] : agent === "gemini" ? ["skills", "extensions", "security"] : agent === "opencode" ? ["plugin", "skills"] : ["version"]);
42043
+ const configText = witness(configPath, agent === "hermes" ? "yaml" : agent === "codex" ? "toml" : "json", agent === "hermes" ? ["skills", "plugins", "hooks"] : agent === "claude" ? ["enabledPlugins", "extraKnownMarketplaces"] : agent === "codex" ? [...CODEX_DISCOVERY_PROJECTION_FIELDS] : agent === "gemini" ? ["skills", "extensions", "security"] : agent === "opencode" ? ["plugin", "skills"] : agent === "sumi" ? ["skills", "plugin", "plugins", "permissions"] : ["version"]);
41923
42044
  const config = configText === null ? {} : agent === "hermes" ? parseHermesConfig(configText) : parseConfig(configText, configPath, agent === "codex");
41924
42045
  const unresolved = (detail) => {
41925
42046
  throw new Error(`Native discovery is unresolved (${agent}: ${detail}); provide a reviewed --discovery-inputs file`);
41926
42047
  };
42048
+ if (agent === "sumi") {
42049
+ const directory = sumiConfigDirectory(home);
42050
+ if (witness(join22(directory, "sumi.jsonc")) !== null)
42051
+ unresolved("JSONC configuration requires a supported format adapter");
42052
+ for (const root2 of [directory, join22(home, ".claude"), join22(home, ".agents")])
42053
+ for (const name of ["skill", "skills"])
42054
+ roots.add(join22(root2, name));
42055
+ if (config.skills !== undefined && (!Array.isArray(config.skills) || config.skills.some((path) => typeof path !== "string")))
42056
+ unresolved("skills must be a string array");
42057
+ for (const value of config.skills ?? []) {
42058
+ if (typeof value !== "string" || /[\0$]/.test(value) || !value || !(isAbsolute16(value) || value.startsWith("~/")))
42059
+ unresolved("remote or relative skill sources need a dedicated discovery adapter");
42060
+ roots.add(value.startsWith("~/") ? join22(home, value.slice(2)) : value);
42061
+ }
42062
+ for (const key of ["plugin", "plugins"])
42063
+ if (config[key] !== undefined && !Array.isArray(config[key]))
42064
+ unresolved(`${key} must be an array`);
42065
+ const plugins = [join22(directory, "plugin"), join22(directory, "plugins")];
42066
+ for (const path of plugins) {
42067
+ safe4(path);
42068
+ if (lstatSync19(path, { throwIfNoEntry: false })?.isDirectory())
42069
+ for (const name of readdirSync7(path).sort()) {
42070
+ if (name === "skills-cli.js" && path === plugins[1])
42071
+ continue;
42072
+ const target = join22(path, name);
42073
+ if (!lstatSync19(target).isFile())
42074
+ unresolved("local plugin packages need a dedicated discovery adapter");
42075
+ witness(target);
42076
+ }
42077
+ }
42078
+ for (const root2 of roots) {
42079
+ safe4(root2);
42080
+ if (lstatSync19(root2, { throwIfNoEntry: false })?.isDirectory() && readdirSync7(root2).some((name) => name.endsWith(".md")))
42081
+ unresolved("flat markdown skills require a dedicated native migration adapter");
42082
+ }
42083
+ }
41927
42084
  if (agent === "hermes") {
41928
- const profile = witness(join21(home, ".hermes/active_profile"));
42085
+ const profile = witness(join22(home, ".hermes/active_profile"));
41929
42086
  if (profile?.trim() && profile.trim() !== "default")
41930
42087
  unresolved("a non-default profile is active");
41931
42088
  const declared = config.skills?.external_dirs ?? [], paths = typeof declared === "string" ? [declared] : declared;
@@ -41939,7 +42096,7 @@ function resolveAgentDiscovery(options) {
41939
42096
  continue;
41940
42097
  if (normalized.startsWith("~") && normalized !== "~" && !normalized.startsWith("~/"))
41941
42098
  unresolved("user-specific tilde expansion requires a separate discovery adapter");
41942
- const path = normalized === "~" ? home : normalized.startsWith("~/") ? join21(home, normalized.slice(2)) : resolve14(home, ".hermes", normalized);
42099
+ const path = normalized === "~" ? home : normalized.startsWith("~/") ? join22(home, normalized.slice(2)) : resolve15(home, ".hermes", normalized);
41943
42100
  safe4(path);
41944
42101
  roots.add(path);
41945
42102
  }
@@ -41948,8 +42105,8 @@ function resolveAgentDiscovery(options) {
41948
42105
  const executable = Bun.which("gemini");
41949
42106
  if (executable) {
41950
42107
  let packageRoot;
41951
- for (let directory = dirname14(realpathSync6(executable)), depth = 0;depth < 8; directory = dirname14(directory), depth++) {
41952
- const path = join21(directory, "package.json"), raw = read2(path);
42108
+ for (let directory = dirname14(realpathSync7(executable)), depth = 0;depth < 8; directory = dirname14(directory), depth++) {
42109
+ const path = join22(directory, "package.json"), raw = read2(path);
41953
42110
  if (raw !== null && parseConfig(raw, path).name === "@google/gemini-cli") {
41954
42111
  packageRoot = directory;
41955
42112
  witness(path);
@@ -41960,12 +42117,12 @@ function resolveAgentDiscovery(options) {
41960
42117
  }
41961
42118
  if (!packageRoot)
41962
42119
  unresolved("installed Gemini package layout is not recognized");
41963
- const builtinRoot = join21(packageRoot, "bundle/builtin");
42120
+ const builtinRoot = join22(packageRoot, "bundle/builtin");
41964
42121
  safe4(builtinRoot);
41965
- if (!lstatSync18(builtinRoot, { throwIfNoEntry: false })?.isDirectory())
42122
+ if (!lstatSync19(builtinRoot, { throwIfNoEntry: false })?.isDirectory())
41966
42123
  unresolved("installed Gemini builtin root is missing");
41967
42124
  for (const name of readdirSync7(builtinRoot).sort()) {
41968
- const text2 = witness(join21(builtinRoot, name, "SKILL.md"));
42125
+ const text2 = witness(join22(builtinRoot, name, "SKILL.md"));
41969
42126
  const match = text2?.match(/^---\r?\n[\s\S]*?^name:\s*([a-z0-9][a-z0-9-]*)\s*$/m);
41970
42127
  if (!match?.[1] || builtinNames.includes(match[1]))
41971
42128
  unresolved("installed Gemini builtin name is missing or ambiguous");
@@ -42007,39 +42164,39 @@ function resolveAgentDiscovery(options) {
42007
42164
  function plugin(root2) {
42008
42165
  root2 = canonical6(root2);
42009
42166
  safe4(root2);
42010
- const manifestPath = join21(root2, agent === "claude" ? ".claude-plugin/plugin.json" : ".codex-plugin/plugin.json");
42167
+ const manifestPath = join22(root2, agent === "claude" ? ".claude-plugin/plugin.json" : ".codex-plugin/plugin.json");
42011
42168
  const raw = witness(manifestPath);
42012
42169
  if (raw === null)
42013
42170
  unresolved("plugin manifest missing");
42014
42171
  const manifest = parseConfig(raw, manifestPath);
42015
- const hooks = witness(join21(root2, "hooks/hooks.json"));
42172
+ const hooks = witness(join22(root2, "hooks/hooks.json"));
42016
42173
  if (manifest.hooks !== undefined || hooks !== null)
42017
42174
  unresolved("plugin hooks require a separate no-skill-injection review");
42018
- const commands = join21(root2, "commands");
42175
+ const commands = join22(root2, "commands");
42019
42176
  safe4(commands);
42020
- if (agent === "claude" && (manifest.commands !== undefined || lstatSync18(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync7(commands).length))
42177
+ if (agent === "claude" && (manifest.commands !== undefined || lstatSync19(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync7(commands).length))
42021
42178
  unresolved("legacy command discovery requires retirement or a dedicated format adapter");
42022
- const rootSkill = witness(join21(root2, "SKILL.md"));
42179
+ const rootSkill = witness(join22(root2, "SKILL.md"));
42023
42180
  if (rootSkill !== null)
42024
42181
  roots.add(root2);
42025
42182
  const declared = manifest.skills === undefined ? ["./skills"] : typeof manifest.skills === "string" ? [manifest.skills] : manifest.skills;
42026
42183
  if (!Array.isArray(declared) || declared.some((path) => typeof path !== "string"))
42027
42184
  unresolved("unsupported plugin skill paths");
42028
42185
  if (agent === "claude")
42029
- roots.add(join21(root2, "skills"));
42186
+ roots.add(join22(root2, "skills"));
42030
42187
  for (const value of declared) {
42031
- const path = resolve14(root2, value);
42188
+ const path = resolve15(root2, value);
42032
42189
  if (path !== root2 && !path.startsWith(root2 + sep4))
42033
42190
  unresolved("plugin skill path escapes its root");
42034
42191
  roots.add(path.endsWith(`${sep4}SKILL.md`) ? dirname14(path) : path);
42035
42192
  }
42036
42193
  }
42037
42194
  if (agent === "claude") {
42038
- const registrations = witness(join21(home, ".claude/plugins/installed_plugins.json"));
42039
- const installed = registrations === null ? {} : parseConfig(registrations, join21(home, ".claude/plugins/installed_plugins.json")).plugins;
42040
- const commands = canonical6(join21(home, ".claude/commands"));
42195
+ const registrations = witness(join22(home, ".claude/plugins/installed_plugins.json"));
42196
+ const installed = registrations === null ? {} : parseConfig(registrations, join22(home, ".claude/plugins/installed_plugins.json")).plugins;
42197
+ const commands = canonical6(join22(home, ".claude/commands"));
42041
42198
  safe4(commands);
42042
- if (lstatSync18(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync7(commands).length)
42199
+ if (lstatSync19(commands, { throwIfNoEntry: false })?.isDirectory() && readdirSync7(commands).length)
42043
42200
  unresolved("legacy home command discovery requires a dedicated format adapter");
42044
42201
  for (const [id2, enabled] of Object.entries(config.enabledPlugins ?? {})) {
42045
42202
  if (enabled === false)
@@ -42061,16 +42218,16 @@ function resolveAgentDiscovery(options) {
42061
42218
  const market = config.marketplaces?.[marketplace] ?? (marketplace === "personal" ? { source_type: "local", source: home } : undefined);
42062
42219
  if (split < 1 || market?.source_type !== "local" || typeof market.source !== "string" || !isAbsolute16(market.source))
42063
42220
  unresolved("enabled plugin marketplace is not an explicit local source");
42064
- const catalogText = witness(join21(market.source, ".agents/plugins/marketplace.json"));
42221
+ const catalogText = witness(join22(market.source, ".agents/plugins/marketplace.json"));
42065
42222
  if (catalogText === null)
42066
42223
  unresolved("marketplace catalog missing");
42067
- const catalog = parseConfig(catalogText, join21(market.source, ".agents/plugins/marketplace.json")), matches = Array.isArray(catalog.plugins) ? catalog.plugins.filter((item) => item.name === name) : [];
42224
+ const catalog = parseConfig(catalogText, join22(market.source, ".agents/plugins/marketplace.json")), matches = Array.isArray(catalog.plugins) ? catalog.plugins.filter((item) => item.name === name) : [];
42068
42225
  if (matches.length !== 1 || matches[0]?.source?.source !== "local" || typeof matches[0]?.source?.path !== "string")
42069
42226
  unresolved("plugin catalog source is missing or ambiguous");
42070
- plugin(resolve14(market.source, matches[0].source.path));
42227
+ plugin(resolve15(market.source, matches[0].source.path));
42071
42228
  }
42072
42229
  } else if (agent === "opencode") {
42073
- if (witness(join21(home, ".config/opencode/opencode.jsonc")) !== null || witness(join21(home, ".config/opencode/config.json")) !== null)
42230
+ if (witness(join22(home, ".config/opencode/opencode.jsonc")) !== null || witness(join22(home, ".config/opencode/config.json")) !== null)
42074
42231
  unresolved("additional config layers require review");
42075
42232
  if ((config.plugin?.length ?? 0) > 0 || config.skills?.urls?.length)
42076
42233
  unresolved("external plugin or remote skill source");
@@ -42079,14 +42236,17 @@ function resolveAgentDiscovery(options) {
42079
42236
  unresolved("relative or malformed added skill root");
42080
42237
  roots.add(path);
42081
42238
  }
42082
- const localPlugins = join21(home, ".config/opencode/plugins");
42239
+ const localPlugins = join22(home, ".config/opencode/plugins");
42083
42240
  safe4(localPlugins);
42084
- if (lstatSync18(localPlugins, { throwIfNoEntry: false }) && readdirSync7(localPlugins).some((name) => name !== "skills-cli.js"))
42241
+ if (lstatSync19(localPlugins, { throwIfNoEntry: false }) && readdirSync7(localPlugins).some((name) => name !== "skills-cli.js"))
42085
42242
  unresolved("additional local plugin hooks require review");
42243
+ } else if (agent === "sumi") {
42244
+ if ((config.plugin?.length ?? 0) > 0 || (config.plugins?.length ?? 0) > 0 || sources.some((source) => source.path !== canonical6(configPath) && source.path !== canonical6(join22(sumiConfigDirectory(home), "sumi.jsonc")) && source.sha256 !== null))
42245
+ unresolved("external or foreign local plugins require review");
42086
42246
  } else if (agent === "hermes") {
42087
- for (const directory of [join21(home, ".hermes/plugins"), join21(home, ".hermes/hermes-agent")]) {
42247
+ for (const directory of [join22(home, ".hermes/plugins"), join22(home, ".hermes/hermes-agent")]) {
42088
42248
  safe4(directory);
42089
- if (lstatSync18(directory, { throwIfNoEntry: false }))
42249
+ if (lstatSync19(directory, { throwIfNoEntry: false }))
42090
42250
  unresolved("installed runtime/plugin discovery requires reviewed source bindings");
42091
42251
  }
42092
42252
  if (Bun.which("hermes") || Object.keys(config.plugins ?? {}).length)
@@ -42094,28 +42254,28 @@ function resolveAgentDiscovery(options) {
42094
42254
  } else if (agent === "gemini") {
42095
42255
  if (Object.keys(config.extensions ?? {}).length || config.skills?.paths?.length)
42096
42256
  unresolved("custom extension or skill paths");
42097
- const directory = join21(home, ".gemini/extensions");
42257
+ const directory = join22(home, ".gemini/extensions");
42098
42258
  safe4(directory);
42099
- if (lstatSync18(directory, { throwIfNoEntry: false }))
42259
+ if (lstatSync19(directory, { throwIfNoEntry: false }))
42100
42260
  for (const name of readdirSync7(directory)) {
42101
- const root2 = join21(directory, name);
42261
+ const root2 = join22(directory, name);
42102
42262
  safe4(root2);
42103
- if (!lstatSync18(root2)?.isDirectory())
42263
+ if (!lstatSync19(root2)?.isDirectory())
42104
42264
  continue;
42105
- const raw = witness(join21(root2, "gemini-extension.json"));
42265
+ const raw = witness(join22(root2, "gemini-extension.json"));
42106
42266
  if (raw === null)
42107
42267
  unresolved("extension registration missing");
42108
- const manifest = parseConfig(raw, join21(root2, "gemini-extension.json"));
42109
- if (manifest.hooks !== undefined || witness(join21(root2, "hooks/hooks.json")) !== null || witness(join21(root2, ".gemini-extension-install.json")) !== null)
42268
+ const manifest = parseConfig(raw, join22(root2, "gemini-extension.json"));
42269
+ if (manifest.hooks !== undefined || witness(join22(root2, "hooks/hooks.json")) !== null || witness(join22(root2, ".gemini-extension-install.json")) !== null)
42110
42270
  unresolved("extension hooks or linked registration require review");
42111
- roots.add(join21(root2, "skills"));
42271
+ roots.add(join22(root2, "skills"));
42112
42272
  }
42113
42273
  }
42114
- return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([join21(home, ".hermes/plugins"), join21(home, ".hermes/hermes-agent")].map((path) => canonical6(path))) } : {} };
42274
+ return { agent, roots: [...roots].sort(), sources, method: "automatic", ...agent === "gemini" ? { builtinNames } : {}, ...agent === "hermes" ? { directories: captureDiscoveryDirectories([join22(home, ".hermes/plugins"), join22(home, ".hermes/hermes-agent")].map((path) => canonical6(path))) } : {} };
42115
42275
  }
42116
42276
 
42117
42277
  // src/lib/agent-adapters.ts
42118
- var INTEGRATION_AGENTS = ["claude", "codex", "gemini", "opencode", "cursor", "hermes"];
42278
+ var INTEGRATION_AGENTS = ["claude", "codex", "gemini", "opencode", "cursor", "hermes", "sumi"];
42119
42279
  function renderAgentHookCommand(command, agent, profileId, event) {
42120
42280
  if (typeof profileId !== "string" || !/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(profileId) || profileId.includes(".."))
42121
42281
  throw new Error("Invalid selection profile id");
@@ -42126,6 +42286,7 @@ var AGENT_ADAPTERS = {
42126
42286
  codex: { root: ".codex/skills", config: ".codex/hooks.json", events: ["UserPromptSubmit", "SessionStart", "SubagentStart"], promptContext: true },
42127
42287
  gemini: { root: ".gemini/skills", config: ".gemini/settings.json", events: ["BeforeAgent", "SessionStart"], promptContext: true },
42128
42288
  opencode: { root: ".config/opencode/skills", config: ".config/opencode/opencode.json", events: ["chat.message"], promptContext: true },
42289
+ sumi: { root: ".hasna-internal/sumi/config/skills", config: ".hasna-internal/sumi/config/sumi.json", events: ["prompt", "context"], promptContext: true },
42129
42290
  hermes: { root: ".hermes/skills", config: ".hermes/config.yaml", events: ["pre_llm_call", "pre_tool_call"], promptContext: true, promptFailureMode: "open", toolFailureMode: "supervised-child-errors-block", requiresNativeTrust: true },
42130
42291
  cursor: { root: ".cursor/skills", config: ".cursor/hooks.json", events: ["beforeSubmitPrompt", "sessionStart"], promptContext: false }
42131
42292
  };
@@ -42482,11 +42643,11 @@ function isSystemRootAlias(path) {
42482
42643
  const target = `/private${path}`, link = `private${path}`;
42483
42644
  const identity4 = (stat2) => `${stat2.dev}:${stat2.ino}:${stat2.ctimeNs}:${stat2.uid}:${stat2.mode}`;
42484
42645
  try {
42485
- const before = lstatSync19(path, { bigint: true });
42646
+ const before = lstatSync20(path, { bigint: true });
42486
42647
  if (!before.isSymbolicLink() || before.uid !== 0n || readlinkSync4(path) !== link)
42487
42648
  return false;
42488
42649
  const directories = ["/", "/private", target].map((directory) => {
42489
- const stat2 = lstatSync19(directory, { bigint: true });
42650
+ const stat2 = lstatSync20(directory, { bigint: true });
42490
42651
  if (!stat2.isDirectory() || stat2.uid !== 0n)
42491
42652
  throw new Error("Untrusted system alias directory");
42492
42653
  if (directory !== "/private/tmp") {
@@ -42503,23 +42664,23 @@ function isSystemRootAlias(path) {
42503
42664
  }
42504
42665
  return { directory, identity: identity4(stat2) };
42505
42666
  });
42506
- return realpathSync7(path) === target && readlinkSync4(path) === link && identity4(lstatSync19(path, { bigint: true })) === identity4(before) && directories.every((item) => identity4(lstatSync19(item.directory, { bigint: true })) === item.identity);
42667
+ return realpathSync8(path) === target && readlinkSync4(path) === link && identity4(lstatSync20(path, { bigint: true })) === identity4(before) && directories.every((item) => identity4(lstatSync20(item.directory, { bigint: true })) === item.identity);
42507
42668
  } catch {
42508
42669
  return false;
42509
42670
  }
42510
42671
  }
42511
42672
  function canonicalSystemPath(path) {
42512
- const absolute = resolve15(path), root2 = `/${absolute.split(sep5)[1]}`;
42513
- if (process.platform !== "darwin" || !["/var", "/tmp", "/etc"].includes(root2) || !lstatSync19(root2, { throwIfNoEntry: false })?.isSymbolicLink())
42673
+ const absolute = resolve16(path), root2 = `/${absolute.split(sep5)[1]}`;
42674
+ if (process.platform !== "darwin" || !["/var", "/tmp", "/etc"].includes(root2) || !lstatSync20(root2, { throwIfNoEntry: false })?.isSymbolicLink())
42514
42675
  return absolute;
42515
42676
  if (!isSystemRootAlias(root2))
42516
42677
  throw new Error(`Refusing symlink path: ${root2}`);
42517
42678
  return `/private${absolute}`;
42518
42679
  }
42519
42680
  function assertSafePath(path) {
42520
- let cursor = resolve15(path);
42681
+ let cursor = resolve16(path);
42521
42682
  while (true) {
42522
- if (lstatSync19(cursor, { throwIfNoEntry: false })?.isSymbolicLink() && !isSystemRootAlias(cursor))
42683
+ if (lstatSync20(cursor, { throwIfNoEntry: false })?.isSymbolicLink() && !isSystemRootAlias(cursor))
42523
42684
  throw new Error(`Refusing symlink path: ${cursor}`);
42524
42685
  const parent = dirname15(cursor);
42525
42686
  if (parent === cursor)
@@ -42529,16 +42690,16 @@ function assertSafePath(path) {
42529
42690
  }
42530
42691
  function readRootAlias(home, agent) {
42531
42692
  assertSafePath(home);
42532
- const realHome = realpathSync7(home), alias = join22(realHome, `.${agent}`);
42533
- const stat2 = lstatSync19(alias, { throwIfNoEntry: false, bigint: true });
42693
+ const realHome = realpathSync8(home), alias = join23(realHome, `.${agent}`);
42694
+ const stat2 = lstatSync20(alias, { throwIfNoEntry: false, bigint: true });
42534
42695
  if (!stat2?.isSymbolicLink())
42535
42696
  throw new Error(`Agent root alias changed after planning: ${alias}`);
42536
- const link = readlinkSync4(alias), targetPath = resolve15(dirname15(alias), link);
42697
+ const link = readlinkSync4(alias), targetPath = resolve16(dirname15(alias), link);
42537
42698
  assertSafePath(targetPath);
42538
- const targetStat = lstatSync19(targetPath, { throwIfNoEntry: false });
42699
+ const targetStat = lstatSync20(targetPath, { throwIfNoEntry: false });
42539
42700
  if (!targetStat?.isDirectory())
42540
42701
  throw new Error(`Agent root alias must target an existing directory: ${alias}`);
42541
- const target = realpathSync7(targetPath), inside = relative4(realHome, target);
42702
+ const target = realpathSync8(targetPath), inside = relative4(realHome, target);
42542
42703
  if (!inside || inside === ".." || inside.startsWith(`..${sep5}`) || isAbsolute17(inside))
42543
42704
  throw new Error(`Agent root alias target must be inside the real home: ${alias}`);
42544
42705
  return { agent, home: realHome, alias, target, link, aliasIdentity: `${stat2.dev}:${stat2.ino}:${stat2.ctimeNs}`, targetIdentity: `${targetStat.dev}:${targetStat.ino}` };
@@ -42548,7 +42709,7 @@ function rootAliases(home, allowed = false) {
42548
42709
  return [];
42549
42710
  const result = [];
42550
42711
  for (const agent of ["claude", "codex"])
42551
- if (lstatSync19(join22(home, `.${agent}`), { throwIfNoEntry: false })?.isSymbolicLink())
42712
+ if (lstatSync20(join23(home, `.${agent}`), { throwIfNoEntry: false })?.isSymbolicLink())
42552
42713
  result.push(readRootAlias(home, agent));
42553
42714
  if (result.some((item, index) => result.slice(index + 1).some((other) => item.target === other.target || item.target.startsWith(other.target + sep5) || other.target.startsWith(item.target + sep5))))
42554
42715
  throw new Error("Agent root alias targets must not overlap");
@@ -42556,7 +42717,7 @@ function rootAliases(home, allowed = false) {
42556
42717
  }
42557
42718
  function canonicalAgentPath(path, aliases) {
42558
42719
  const absolute = canonicalSystemPath(path), binding = aliases.find((item) => absolute === item.alias || absolute.startsWith(item.alias + sep5));
42559
- return binding ? join22(binding.target, relative4(binding.alias, absolute)) : absolute;
42720
+ return binding ? join23(binding.target, relative4(binding.alias, absolute)) : absolute;
42560
42721
  }
42561
42722
  function disabledCodexSkillPaths(config, aliases) {
42562
42723
  const skills = config.skills;
@@ -42575,7 +42736,7 @@ function disabledCodexSkillPaths(config, aliases) {
42575
42736
  continue;
42576
42737
  let document2;
42577
42738
  try {
42578
- document2 = realpathSync7(canonicalAgentPath(entry.path, aliases));
42739
+ document2 = realpathSync8(canonicalAgentPath(entry.path, aliases));
42579
42740
  } catch {
42580
42741
  continue;
42581
42742
  }
@@ -42587,7 +42748,7 @@ function disabledCodexSkillPaths(config, aliases) {
42587
42748
  }
42588
42749
  function recheckRootAliases(aliases) {
42589
42750
  for (const binding of aliases) {
42590
- if (!["claude", "codex"].includes(binding.agent) || binding.alias !== join22(binding.home, `.${binding.agent}`))
42751
+ if (!["claude", "codex"].includes(binding.agent) || binding.alias !== join23(binding.home, `.${binding.agent}`))
42591
42752
  throw new Error("Invalid agent root alias binding");
42592
42753
  const current = readRootAlias(binding.home, binding.agent);
42593
42754
  if (JSON.stringify(current) !== JSON.stringify(binding))
@@ -42596,7 +42757,7 @@ function recheckRootAliases(aliases) {
42596
42757
  }
42597
42758
  function readNativeBytes(path, maximum = 64 * 1024 * 1024) {
42598
42759
  assertSafePath(path);
42599
- const before = lstatSync19(path);
42760
+ const before = lstatSync20(path);
42600
42761
  if (!before.isFile() || before.size > maximum)
42601
42762
  throw new Error("Unsupported or oversized native skill file");
42602
42763
  const descriptor = openSync16(path, constants12.O_RDONLY | constants12.O_NOFOLLOW | constants12.O_NONBLOCK);
@@ -42612,7 +42773,7 @@ function readNativeBytes(path, maximum = 64 * 1024 * 1024) {
42612
42773
  break;
42613
42774
  length += count;
42614
42775
  }
42615
- const after = fstatSync16(descriptor), current = lstatSync19(path);
42776
+ const after = fstatSync16(descriptor), current = lstatSync20(path);
42616
42777
  if (current.dev !== opened.dev || current.ino !== opened.ino || current.size !== after.size || current.mtimeMs !== after.mtimeMs || current.ctimeMs !== after.ctimeMs || length !== before.size || after.size !== before.size || after.mtimeMs !== opened.mtimeMs || after.ctimeMs !== opened.ctimeMs)
42617
42778
  throw new Error("Native skill file changed while reading");
42618
42779
  return bytes.subarray(0, length);
@@ -42624,14 +42785,14 @@ function treeHash(root2) {
42624
42785
  const hash2 = createHash18("sha256");
42625
42786
  let bytes = 0, files = 0;
42626
42787
  function visit2(path) {
42627
- const stat2 = lstatSync19(path);
42788
+ const stat2 = lstatSync20(path);
42628
42789
  if (stat2.isSymbolicLink())
42629
42790
  throw new Error(`Refusing symlink in skill: ${path}`);
42630
42791
  const rel = relative4(root2, path);
42631
42792
  if (stat2.isDirectory()) {
42632
42793
  hash2.update(`d\x00${rel}\x00`);
42633
42794
  for (const name of readdirSync8(path).sort())
42634
- visit2(join22(path, name));
42795
+ visit2(join23(path, name));
42635
42796
  return;
42636
42797
  }
42637
42798
  if (!stat2.isFile())
@@ -42653,10 +42814,10 @@ function selectNativeMigrationTargets(inventory, manifest) {
42653
42814
  const identities = new Set;
42654
42815
  const selected = [];
42655
42816
  for (const target of manifest.targets) {
42656
- if (!isAbsolute17(target.projectRoot) || resolve15(target.projectRoot) !== target.projectRoot)
42817
+ if (!isAbsolute17(target.projectRoot) || resolve16(target.projectRoot) !== target.projectRoot)
42657
42818
  throw new Error(`Native migration target project root must be an existing absolute directory: ${target.projectRoot}`);
42658
- const projectRoot = canonicalSystemPath(target.projectRoot), normalized = relative4(projectRoot, resolve15(projectRoot, target.path));
42659
- if (!existsSync6(projectRoot) || !lstatSync19(projectRoot).isDirectory())
42819
+ const projectRoot = canonicalSystemPath(target.projectRoot), normalized = relative4(projectRoot, resolve16(projectRoot, target.path));
42820
+ if (!existsSync7(projectRoot) || !lstatSync20(projectRoot).isDirectory())
42660
42821
  throw new Error(`Native migration target project root must be an existing absolute directory: ${target.projectRoot}`);
42661
42822
  assertSafePath(projectRoot);
42662
42823
  if (isAbsolute17(target.path) || target.path.includes("\\") || target.path.includes("\x00") || !normalized || normalized === ".." || normalized.startsWith(`..${sep5}`) || normalized !== target.path || !/^[0-9a-f]{64}$/.test(target.treeSha256))
@@ -42665,8 +42826,8 @@ function selectNativeMigrationTargets(inventory, manifest) {
42665
42826
  if (identities.has(identity4))
42666
42827
  throw new Error(`Duplicate native migration target: ${target.path}`);
42667
42828
  identities.add(identity4);
42668
- const expected = canonicalSystemPath(resolve15(target.projectRoot, target.path));
42669
- const matches = inventory.filter((entry2) => entry2.agent === target.agent && resolve15(entry2.path) === expected);
42829
+ const expected = canonicalSystemPath(resolve16(target.projectRoot, target.path));
42830
+ const matches = inventory.filter((entry2) => entry2.agent === target.agent && resolve16(entry2.path) === expected);
42670
42831
  if (matches.length !== 1)
42671
42832
  throw new Error(`Native migration target was not found exactly once: ${target.agent} ${target.projectRoot}/${target.path}`);
42672
42833
  const entry = matches[0];
@@ -42695,9 +42856,9 @@ function projectAncestorDirectories(projects) {
42695
42856
  }
42696
42857
  function inventoryNativeSkills(home = homedir3(), options = {}) {
42697
42858
  home = canonicalSystemPath(home);
42698
- if (options.reviewedCacheAlias !== undefined && (!options.includeVendor || !isAbsolute17(options.reviewedCacheAlias) || resolve15(options.reviewedCacheAlias) !== options.reviewedCacheAlias))
42859
+ if (options.reviewedCacheAlias !== undefined && (!options.includeVendor || !isAbsolute17(options.reviewedCacheAlias) || resolve16(options.reviewedCacheAlias) !== options.reviewedCacheAlias))
42699
42860
  throw new Error("A reviewed cache alias requires vendor inventory and an exact absolute path");
42700
- if (options.disabledVendorPaths?.some((path) => !isAbsolute17(path) || resolve15(path) !== path))
42861
+ if (options.disabledVendorPaths?.some((path) => !isAbsolute17(path) || resolve16(path) !== path))
42701
42862
  throw new Error("Disabled vendor paths must be exact absolute paths");
42702
42863
  const reviewedCacheAlias = options.reviewedCacheAlias === undefined ? undefined : canonicalSystemPath(options.reviewedCacheAlias);
42703
42864
  const disabledVendorPaths = new Set((options.disabledVendorPaths ?? []).map(canonicalSystemPath));
@@ -42705,14 +42866,18 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
42705
42866
  const selectedAgents = options.agents ? new Set(options.agents) : undefined;
42706
42867
  const includesAgent = (agent) => !selectedAgents || selectedAgents.has(agent);
42707
42868
  const rootDefinitions = selectedAgents ? ROOTS.filter(([agent, path]) => selectedAgents.has(agent) || selectedAgents.has("hermes") && agent === "codex" && path === ".agents/skills") : ROOTS;
42708
- const roots = rootDefinitions.map(([agent, path]) => [agent, canonicalAgentPath(join22(home, path), aliases)]);
42709
- const bridgePaths = Object.values(AGENT_ADAPTERS).map((adapter) => canonicalAgentPath(join22(home, adapter.root, CLI_BRIDGE_NAME), aliases));
42869
+ const roots = rootDefinitions.map(([agent, path]) => [agent, canonicalAgentPath(join23(home, path), aliases)]);
42870
+ const bridgePaths = Object.entries(AGENT_ADAPTERS).filter(([agent]) => agent !== "sumi" || includesAgent("sumi")).map(([agent, adapter]) => canonicalAgentPath(join23(agent === "sumi" ? sumiBridgeRoot(home) : join23(home, adapter.root), CLI_BRIDGE_NAME), aliases));
42710
42871
  for (const project of projectAncestorDirectories([...options.projectDirs ?? [], ...options.projectDir ? [options.projectDir] : []])) {
42711
42872
  for (const [agent, path] of rootDefinitions)
42712
- roots.push([agent, canonicalAgentPath(join22(project, path), aliases)]);
42873
+ roots.push([agent, canonicalAgentPath(join23(project, path), aliases)]);
42874
+ if (selectedAgents?.has("sumi"))
42875
+ for (const directory of [".claude", ".agents"])
42876
+ for (const name of ["skill", "skills"])
42877
+ roots.push(["sumi", canonicalAgentPath(join23(project, directory, name), aliases)]);
42713
42878
  }
42714
42879
  const installationInputs = options.codexInstallationInputRoots ?? [];
42715
- if (installationInputs.some((input) => resolve15(input) !== input || realpathSync7(input) !== input || roots.some(([agent, path]) => agent === "codex" && (path === input || path.startsWith(input + sep5) || input.startsWith(path + sep5)))))
42880
+ if (installationInputs.some((input) => resolve16(input) !== input || realpathSync8(input) !== input || roots.some(([agent, path]) => agent === "codex" && (path === input || path.startsWith(input + sep5) || input.startsWith(path + sep5)))))
42716
42881
  throw new Error("Native installation input overlaps an unconditional skill-loading root");
42717
42882
  const entries = [], seen = new Set;
42718
42883
  const cacheScans = new Map, maxAliasProofEntries = 1e4;
@@ -42726,13 +42891,13 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
42726
42891
  }
42727
42892
  let reviewedCacheAliasFound = false;
42728
42893
  function verifiedSiblingCacheAlias(agent, path, parent) {
42729
- const link = readlinkSync4(path), lexicalTarget = resolve15(parent, link);
42894
+ const link = readlinkSync4(path), lexicalTarget = resolve16(parent, link);
42730
42895
  if (isAbsolute17(link) ? link !== lexicalTarget : dirname15(link) !== ".")
42731
42896
  return false;
42732
42897
  const target = canonicalSystemPath(lexicalTarget);
42733
42898
  if (dirname15(target) !== parent)
42734
42899
  return false;
42735
- if (!lstatSync19(target, { throwIfNoEntry: false })?.isDirectory())
42900
+ if (!lstatSync20(target, { throwIfNoEntry: false })?.isDirectory())
42736
42901
  return false;
42737
42902
  const scan = cacheScans.get(target);
42738
42903
  if (!scan?.complete || scan.entries > maxAliasProofEntries)
@@ -42755,37 +42920,40 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
42755
42920
  assertSafePath(path);
42756
42921
  if (configuredRoot && agent === "codex" && installationInputs.some((root2) => path === root2 || path.startsWith(`${root2}${sep5}`)))
42757
42922
  return scan;
42758
- if (!existsSync6(path))
42923
+ if (!existsSync7(path))
42759
42924
  return scan;
42760
- const stat2 = lstatSync19(path);
42761
- if (stat2.isFile())
42925
+ const stat2 = lstatSync20(path);
42926
+ if (stat2.isFile()) {
42927
+ if (agent === "sumi" && depth === 1 && path.endsWith(".md"))
42928
+ throw new Error("NATIVE_SKILL_DRIFT: flat Sumi skill documents require a dedicated migration adapter");
42762
42929
  return scan;
42930
+ }
42763
42931
  if (!stat2.isDirectory())
42764
42932
  throw new Error(`Unsupported native discovery entry: ${path}`);
42765
- if (existsSync6(join22(path, "SKILL.md"))) {
42933
+ if (existsSync7(join23(path, "SKILL.md"))) {
42766
42934
  scan.hasSkills = true;
42767
42935
  if (seen.has(path))
42768
42936
  return scan;
42769
42937
  seen.add(path);
42770
42938
  let managed = false;
42771
- const marker = join22(path, ".hasna-skills.json");
42772
- if (existsSync6(marker)) {
42939
+ const marker = join23(path, ".hasna-skills.json");
42940
+ if (existsSync7(marker)) {
42773
42941
  try {
42774
42942
  managed = JSON.parse(readFileSync14(marker, "utf8")).managedBy === "@hasna/skills";
42775
42943
  } catch {}
42776
42944
  }
42777
- const bridge = !vendor && isOwnedCliBridge(path, bridgePaths);
42945
+ const bridge = (!vendor || agent === "sumi") && isOwnedCliBridge(path, bridgePaths);
42778
42946
  const rootAlias = aliases.find((item) => path === item.target || path.startsWith(item.target + sep5));
42779
- entries.push({ agent, path, hash: treeHash(path), managed, vendor, ...agent === "codex" && path.startsWith(canonicalAgentPath(join22(home, ".codex", "skills", ".system"), aliases) + sep5) ? { system: true } : {}, ...bridge ? { bridge: true, bridgeHome: resolve15(home) } : {}, ...rootAlias ? { rootAlias } : {} });
42947
+ entries.push({ agent, path, hash: treeHash(path), managed, vendor, ...agent === "codex" && path.startsWith(canonicalAgentPath(join23(home, ".codex", "skills", ".system"), aliases) + sep5) ? { system: true } : {}, ...bridge ? { bridge: true, bridgeHome: resolve16(home) } : {}, ...rootAlias ? { rootAlias } : {} });
42780
42948
  return scan;
42781
42949
  }
42782
- if (depth > (vendor ? 32 : 3))
42950
+ if (depth > (agent === "sumi" ? 32 : vendor ? 32 : 3))
42783
42951
  return { ...scan, complete: false };
42784
42952
  const children = [], directory = opendirSync5(path);
42785
42953
  try {
42786
42954
  let child;
42787
42955
  while ((child = directory.readSync()) !== null) {
42788
- admit(join22(path, child.name));
42956
+ admit(join23(path, child.name));
42789
42957
  children.push(child);
42790
42958
  }
42791
42959
  } finally {
@@ -42797,13 +42965,13 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
42797
42965
  for (const { name } of children) {
42798
42966
  if (name === "node_modules")
42799
42967
  continue;
42800
- if (name.startsWith(".") && name !== ".system" && agent !== "hermes" && !(options.guardHermes && `${path}${sep5}`.includes(`${sep5}.agents${sep5}skills${sep5}`)))
42968
+ if (name.startsWith(".") && name !== ".system" && agent !== "hermes" && agent !== "sumi" && !(options.guardHermes && `${path}${sep5}`.includes(`${sep5}.agents${sep5}skills${sep5}`)))
42801
42969
  continue;
42802
42970
  const isVendor = vendor || name === ".system";
42803
42971
  if (isVendor && !options.includeVendor)
42804
42972
  continue;
42805
- const child = join22(path, name);
42806
- if (isVendor && lstatSync19(child, { throwIfNoEntry: false })?.isSymbolicLink()) {
42973
+ const child = join23(path, name);
42974
+ if (isVendor && lstatSync20(child, { throwIfNoEntry: false })?.isSymbolicLink()) {
42807
42975
  const target = statSync6(child, { throwIfNoEntry: false });
42808
42976
  if (target?.isFile() || pluginCache && target?.isDirectory() && verifiedSiblingCacheAlias(agent, child, path)) {
42809
42977
  scan.entries++;
@@ -42829,11 +42997,11 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
42829
42997
  scanRoot(agent, path);
42830
42998
  if (options.includeVendor) {
42831
42999
  for (const agent of ["codex", "claude"].filter(includesAgent))
42832
- scanRoot(agent, canonicalAgentPath(join22(home, `.${agent}`, "plugins", "cache"), aliases), true, true);
43000
+ scanRoot(agent, canonicalAgentPath(join23(home, `.${agent}`, "plugins", "cache"), aliases), true, true);
42833
43001
  if (includesAgent("claude"))
42834
- scanRoot("claude", canonicalAgentPath(join22(home, ".claude", "plugins", "synced"), aliases), true);
43002
+ scanRoot("claude", canonicalAgentPath(join23(home, ".claude", "plugins", "synced"), aliases), true);
42835
43003
  if (includesAgent("gemini"))
42836
- scanRoot("gemini", join22(home, ".gemini", "extensions"), true);
43004
+ scanRoot("gemini", join23(home, ".gemini", "extensions"), true);
42837
43005
  }
42838
43006
  const configured = options.configured ? INTEGRATION_AGENTS.filter(includesAgent).flatMap((agent) => resolveAgentDiscovery({ home, agent, reviewed: options.discoveryInputs, canonical: (path) => canonicalAgentPath(path, aliases) }).roots.map((path) => ({ agent, path }))) : [];
42839
43007
  for (const root2 of [...options.agentRoots ?? [], ...configured])
@@ -42846,7 +43014,7 @@ function inventoryNativeSkills(home = homedir3(), options = {}) {
42846
43014
  }
42847
43015
  function readOptional(path) {
42848
43016
  assertSafePath(path);
42849
- return existsSync6(path) ? readFileSync14(path, "utf8") : null;
43017
+ return existsSync7(path) ? readFileSync14(path, "utf8") : null;
42850
43018
  }
42851
43019
  function jsonObject(text2, path) {
42852
43020
  if (text2 === null)
@@ -42946,19 +43114,19 @@ function configureHooks(config, agent, command, profileId, nativeReady) {
42946
43114
  function disableCodexSkills(text2, skills, aliases, bridgePath) {
42947
43115
  const bundled = disableCodexBundledSkills(text2);
42948
43116
  let result = normalizeCodexInlinePathConfig(bundled);
42949
- const bridgeSelector = (entry) => typeof entry.name === "string" && entry.name.trim() === CLI_BRIDGE_NAME || typeof entry.path === "string" && [resolve15(bridgePath), resolve15(join22(bridgePath, "SKILL.md"))].includes(canonicalAgentPath(entry.path, aliases));
43117
+ const bridgeSelector = (entry) => typeof entry.name === "string" && entry.name.trim() === CLI_BRIDGE_NAME || typeof entry.path === "string" && [resolve16(bridgePath), resolve16(join23(bridgePath, "SKILL.md"))].includes(canonicalAgentPath(entry.path, aliases));
42950
43118
  const previousConfig = Bun.TOML.parse(bundled).skills?.config;
42951
43119
  if (previousConfig !== undefined && (!Array.isArray(previousConfig) || previousConfig.some((entry) => !entry || typeof entry !== "object" || entry.path !== undefined && entry.name !== undefined)))
42952
43120
  throw new Error("Codex skill controls require one path or name selector per [[skills.config]] entry; review ambiguous entries before running skills hook install");
42953
43121
  const bridgeNeedsRepair = previousConfig?.some((entry) => entry.enabled === false && bridgeSelector(entry));
42954
43122
  const selections = [...skills.filter((entry) => entry.agent === "codex" && !entry.bridge).map((skill) => ({ path: skill.path, enabled: false })), { path: bridgePath, enabled: true }];
42955
43123
  for (const skill of selections) {
42956
- const path = join22(skill.path, "SKILL.md");
43124
+ const path = join23(skill.path, "SKILL.md");
42957
43125
  let found = false;
42958
43126
  result = result.replace(CODEX_SKILL_CONFIG_SECTIONS, (section) => {
42959
43127
  const parsed = Bun.TOML.parse(section);
42960
43128
  const declared = parsed.skills?.config?.[0];
42961
- if (!declared || !(skill.enabled && bridgeSelector(declared)) && !(typeof declared.path === "string" && [resolve15(path), resolve15(skill.path)].includes(canonicalAgentPath(declared.path, aliases))))
43129
+ if (!declared || !(skill.enabled && bridgeSelector(declared)) && !(typeof declared.path === "string" && [resolve16(path), resolve16(skill.path)].includes(canonicalAgentPath(declared.path, aliases))))
42962
43130
  return section;
42963
43131
  found = true;
42964
43132
  return /^\s*enabled\s*=/m.test(section) ? section.replace(/^\s*enabled\s*=.*$/m, `enabled = ${skill.enabled}`) : `${section.trimEnd()}
@@ -42979,14 +43147,14 @@ enabled = false
42979
43147
  return result;
42980
43148
  }
42981
43149
  function assertCodexInstallationInputs(home, projectDirs, inputs) {
42982
- const nativeRoots = [home, ...projectAncestorDirectories(projectDirs)].flatMap((directory) => ROOTS.filter(([agent]) => agent === "codex").map(([, path]) => resolve15(directory, path)));
43150
+ const nativeRoots = [home, ...projectAncestorDirectories(projectDirs)].flatMap((directory) => ROOTS.filter(([agent]) => agent === "codex").map(([, path]) => resolve16(directory, path)));
42983
43151
  if (inputs.some((input) => nativeRoots.some((root2) => root2 === input || root2.startsWith(input + sep5) || input.startsWith(root2 + sep5))))
42984
43152
  throw new Error("Native installation input overlaps an unconditional skill-loading root");
42985
43153
  }
42986
43154
  function planAgentIntegration(options) {
42987
43155
  const home = options.home ?? homedir3(), dataDir2 = options.dataDir ?? getDataDirReadOnly();
42988
43156
  const aliases = rootAliases(home, options.allowRootAliases);
42989
- const policyPath = join22(dataDir2, "agent-policy.json");
43157
+ const policyPath = join23(dataDir2, "agent-policy.json");
42990
43158
  assertSafePath(policyPath);
42991
43159
  const priorSnapshot = readManagedSkillPolicySnapshot(dataDir2), previousPolicy = priorSnapshot?.text ?? null, policy = priorSnapshot?.value ?? {};
42992
43160
  if (policy.bridge !== undefined && (!policy.bridge || typeof policy.bridge !== "object" || Array.isArray(policy.bridge)))
@@ -43018,10 +43186,10 @@ function planAgentIntegration(options) {
43018
43186
  }
43019
43187
  return resolveAgentDiscovery({ home, agent, reviewed: options.discoveryInputs, retainedReview, canonical: (path) => canonicalAgentPath(path, aliases) });
43020
43188
  });
43021
- const codexConfig = options.agents.includes("codex") ? Bun.TOML.parse(readOptional(canonicalAgentPath(join22(home, ".codex", "config.toml"), aliases)) ?? "") : {};
43189
+ const codexConfig = options.agents.includes("codex") ? Bun.TOML.parse(readOptional(canonicalAgentPath(join23(home, ".codex", "config.toml"), aliases)) ?? "") : {};
43022
43190
  const nativeSkills = inventoryNativeSkills(home, { includeVendor: true, guardHermes: options.agents.includes("hermes"), agents: options.agents, projectDir: options.projectDir, agentRoots: discoveries.flatMap((binding) => binding.roots.map((path) => ({ agent: binding.agent, path }))), allowRootAliases: options.allowRootAliases, reviewedCacheAlias: options.reviewedCacheAlias, disabledVendorPaths: disabledCodexSkillPaths(codexConfig, aliases) });
43023
43191
  const observedNativeSources = [];
43024
- const codexPluginControls = options.codexNativeCatalog ? reviewCodexPluginControls(options.codexNativeCatalog, nativeSkills.filter((entry) => entry.agent === "codex" && entry.vendor).map((entry) => join22(entry.path, "SKILL.md")), canonicalAgentPath(join22(home, ".codex/plugins/cache"), aliases), resolve15(options.projectDir ?? home), (path) => {
43192
+ const codexPluginControls = options.codexNativeCatalog ? reviewCodexPluginControls(options.codexNativeCatalog, nativeSkills.filter((entry) => entry.agent === "codex" && entry.vendor).map((entry) => join23(entry.path, "SKILL.md")), canonicalAgentPath(join23(home, ".codex/plugins/cache"), aliases), resolve16(options.projectDir ?? home), (path) => {
43025
43193
  const bytes = readNativeBytes(path, 1024 * 1024);
43026
43194
  observedNativeSources.push({ path, sha256: sha4(bytes) });
43027
43195
  return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
@@ -43029,7 +43197,7 @@ function planAgentIntegration(options) {
43029
43197
  const codexPluginSkills = codexPluginControls.skills;
43030
43198
  const codexInactivePlugins = codexPluginControls.inactivePlugins;
43031
43199
  const codexDiscovery = discoveries.find((binding) => binding.agent === "codex");
43032
- const codexPluginSourceInputs = codexPluginControls.sourceInputs.filter((input) => codexDiscovery?.method === "reviewed" && codexDiscovery.roots.some((root2) => root2 === input.sourceRoot || root2.startsWith(input.sourceRoot + sep5) || input.sourceRoot.startsWith(root2 + sep5)) && codexDiscovery.sources.some((source) => source.path === join22(input.sourceRoot, ".codex-plugin/plugin.json") && source.sha256 !== null && source.format === undefined && source.fields === undefined));
43200
+ const codexPluginSourceInputs = codexPluginControls.sourceInputs.filter((input) => codexDiscovery?.method === "reviewed" && codexDiscovery.roots.some((root2) => root2 === input.sourceRoot || root2.startsWith(input.sourceRoot + sep5) || input.sourceRoot.startsWith(root2 + sep5)) && codexDiscovery.sources.some((source) => source.path === join23(input.sourceRoot, ".codex-plugin/plugin.json") && source.sha256 !== null && source.format === undefined && source.fields === undefined));
43033
43201
  assertCodexInstallationInputs(home, [options.projectDir ?? home], codexPluginSourceInputs.map((input) => input.sourceRoot));
43034
43202
  const changes = [];
43035
43203
  for (const agent of [...new Set(options.agents)]) {
@@ -43037,19 +43205,19 @@ function planAgentIntegration(options) {
43037
43205
  throw new Error(`Unsupported agent: ${agent}`);
43038
43206
  const { command, profileId: profileId2 } = bindings.get(agent);
43039
43207
  const adapter = AGENT_ADAPTERS[agent];
43040
- const bridgePath = canonicalAgentPath(join22(home, adapter.root, CLI_BRIDGE_NAME), aliases);
43208
+ const bridgePath = canonicalAgentPath(join23(agent === "sumi" ? sumiBridgeRoot(home) : join23(home, adapter.root), CLI_BRIDGE_NAME), aliases);
43041
43209
  assertSafePath(bridgePath);
43042
- if (existsSync6(bridgePath) && !isOwnedCliBridge(bridgePath, [bridgePath]))
43210
+ if (existsSync7(bridgePath) && !isOwnedCliBridge(bridgePath, [bridgePath]))
43043
43211
  throw new Error(`Refusing to overwrite an unrecognized or modified Skills bridge: ${bridgePath}`);
43044
43212
  for (const [name, after2] of Object.entries(CLI_BRIDGE_FILES)) {
43045
- const path2 = join22(bridgePath, name), before2 = readOptional(path2);
43213
+ const path2 = join23(bridgePath, name), before2 = readOptional(path2);
43046
43214
  if (before2 !== after2)
43047
43215
  changes.push({ path: path2, before: before2, after: after2 });
43048
43216
  }
43049
- const path = canonicalAgentPath(join22(home, adapter.config), aliases);
43217
+ const path = canonicalAgentPath(agent === "sumi" ? sumiConfigPath(home) : join23(home, adapter.config), aliases);
43050
43218
  const before = readOptional(path);
43051
43219
  if (agent === "hermes") {
43052
- const supervisorPath = join22(dataDir2, "agent-hooks", "hermes.js"), supervisorBefore = readOptional(supervisorPath), supervisorAfter = renderHermesSupervisor(command, profileId2);
43220
+ const supervisorPath = join23(dataDir2, "agent-hooks", "hermes.js"), supervisorBefore = readOptional(supervisorPath), supervisorAfter = renderHermesSupervisor(command, profileId2);
43053
43221
  const priorCommand = policy.bridge?.commands?.hermes, priorProfile = policy.bridge?.profiles?.hermes ?? policy.profileId;
43054
43222
  const previous = policy.bridge?.supervisors?.hermes;
43055
43223
  if (supervisorBefore !== null && supervisorBefore !== supervisorAfter && !(previous?.path === supervisorPath && typeof priorCommand === "string" && typeof priorProfile === "string" && supervisorBefore === renderHermesSupervisor(priorCommand, priorProfile)))
@@ -43060,19 +43228,30 @@ function planAgentIntegration(options) {
43060
43228
  const after2 = configureHermesHooks(before, supervisor, previous);
43061
43229
  if (before !== after2)
43062
43230
  changes.push({ path, before, after: after2 });
43063
- const optOut = join22(home, ".hermes", HERMES_OPT_OUT), optOutBefore = readOptional(optOut);
43231
+ const optOut = join23(home, ".hermes", HERMES_OPT_OUT), optOutBefore = readOptional(optOut);
43064
43232
  if (optOutBefore === null)
43065
43233
  changes.push({ path: optOut, before: null, after: `Managed by @hasna/skills: bundled native skill reseeding is disabled.
43066
43234
  ` });
43067
43235
  continue;
43068
43236
  }
43069
43237
  const config = jsonObject(before, path);
43070
- if (agent === "opencode") {
43238
+ if (agent === "sumi") {
43239
+ if (config.permissions !== undefined && (!Array.isArray(config.permissions) || config.permissions.some((rule) => !rule || typeof rule.action !== "string" || typeof rule.resource !== "string" || !["allow", "deny", "ask"].includes(rule.effect))))
43240
+ throw new Error("Expected Sumi native permission rules");
43241
+ config.permissions = [...(config.permissions ?? []).filter((rule) => rule.action !== "skill"), ...SUMI_SKILL_PERMISSIONS];
43242
+ const pluginPath = join23(sumiConfigDirectory(home), "plugins", "skills-cli.js"), pluginBefore = readOptional(pluginPath);
43243
+ const pluginAfter = renderSumiPlugin(command, profileId2);
43244
+ const priorCommand = policy.bridge?.commands?.sumi, priorProfile = policy.bridge?.profiles?.sumi ?? policy.profileId;
43245
+ if (pluginBefore !== null && pluginBefore !== pluginAfter && !(typeof priorCommand === "string" && typeof priorProfile === "string" && pluginBefore === renderSumiPlugin(priorCommand, priorProfile)))
43246
+ throw new Error("Refusing to overwrite a modified Sumi Skills plugin; preserve and review it first");
43247
+ if (pluginBefore !== pluginAfter)
43248
+ changes.push({ path: pluginPath, before: pluginBefore, after: pluginAfter });
43249
+ } else if (agent === "opencode") {
43071
43250
  const permission = config.permission ?? {};
43072
43251
  if (!permission || typeof permission !== "object" || Array.isArray(permission))
43073
43252
  throw new Error("Expected OpenCode permission object");
43074
43253
  config.permission = { ...permission, skill: { "*": "deny", [CLI_BRIDGE_NAME]: "allow" } };
43075
- const pluginPath = join22(home, ".config", "opencode", "plugins", "skills-cli.js"), pluginBefore = readOptional(pluginPath);
43254
+ const pluginPath = join23(home, ".config", "opencode", "plugins", "skills-cli.js"), pluginBefore = readOptional(pluginPath);
43076
43255
  const pluginAfter = renderOpenCodePlugin(command, profileId2);
43077
43256
  const priorCommand = policy.bridge?.commands?.opencode;
43078
43257
  const ownedPrevious = typeof priorCommand === "string" && typeof policy.profileId === "string" && pluginBefore === renderOpenCodePlugin(priorCommand, policy.bridge?.profiles?.opencode ?? policy.profileId);
@@ -43089,13 +43268,13 @@ function planAgentIntegration(options) {
43089
43268
  if (before !== after)
43090
43269
  changes.push({ path, before, after });
43091
43270
  if (agent === "codex") {
43092
- const configPath = canonicalAgentPath(join22(home, ".codex", "config.toml"), aliases), previous = readOptional(configPath);
43271
+ const configPath = canonicalAgentPath(join23(home, ".codex", "config.toml"), aliases), previous = readOptional(configPath);
43093
43272
  const next = disableReviewedCodexPluginNames(disableCodexSkills(previous ?? "", nativeSkills, aliases, bridgePath), codexPluginSkills);
43094
43273
  if (next !== (previous ?? ""))
43095
43274
  changes.push({ path: configPath, before: previous, after: next });
43096
43275
  }
43097
43276
  }
43098
- const codexPluginSkillReview = options.codexNativeCatalog ? { version: options.codexNativeCatalog.version, cwd: options.codexNativeCatalog.cwd, catalogSha256: sha4(JSON.stringify({ version: options.codexNativeCatalog.version, cwd: options.codexNativeCatalog.cwd, skills: projectCodexNativeSkillCatalog({ data: [{ cwd: options.codexNativeCatalog.cwd, errors: [], skills: options.codexNativeCatalog.skills }] }, options.codexNativeCatalog.cwd), ...options.codexNativeCatalog.plugins === undefined ? {} : { plugins: projectCodexInstalledPluginEntries(options.codexNativeCatalog.plugins) } })), configSha256: changes.find((change) => change.path === canonicalAgentPath(join22(home, ".codex/config.toml"), aliases))?.before === null ? null : sha4(readOptional(canonicalAgentPath(join22(home, ".codex/config.toml"), aliases)) ?? "") } : policy.bridge?.codexPluginSkillReview;
43277
+ const codexPluginSkillReview = options.codexNativeCatalog ? { version: options.codexNativeCatalog.version, cwd: options.codexNativeCatalog.cwd, catalogSha256: sha4(JSON.stringify({ version: options.codexNativeCatalog.version, cwd: options.codexNativeCatalog.cwd, skills: projectCodexNativeSkillCatalog({ data: [{ cwd: options.codexNativeCatalog.cwd, errors: [], skills: options.codexNativeCatalog.skills }] }, options.codexNativeCatalog.cwd), ...options.codexNativeCatalog.plugins === undefined ? {} : { plugins: projectCodexInstalledPluginEntries(options.codexNativeCatalog.plugins) } })), configSha256: changes.find((change) => change.path === canonicalAgentPath(join23(home, ".codex/config.toml"), aliases))?.before === null ? null : sha4(readOptional(canonicalAgentPath(join23(home, ".codex/config.toml"), aliases)) ?? "") } : policy.bridge?.codexPluginSkillReview;
43099
43278
  const discoveryAfter = discoveries.map((binding) => {
43100
43279
  const rebound = rebindAgentDiscovery(binding, new Map(changes.map((change) => [change.path, change.after])));
43101
43280
  if (binding.agent !== "codex")
@@ -43110,12 +43289,12 @@ function planAgentIntegration(options) {
43110
43289
  version: CLI_BRIDGE_VERSION,
43111
43290
  digest: CLI_BRIDGE_DIGEST,
43112
43291
  agents: [...new Set([...priorAgents, ...options.agents])].sort(),
43113
- home: resolve15(home),
43292
+ home: resolve16(home),
43114
43293
  includeVendor: true,
43115
- ...options.agents.includes("hermes") ? { supervisors: { ...policy.bridge?.supervisors, hermes: { path: join22(dataDir2, "agent-hooks", "hermes.js"), runtime: process.execPath, sha256: sha4(renderHermesSupervisor(bindings.get("hermes").command, bindings.get("hermes").profileId)) } } } : {},
43294
+ ...options.agents.includes("hermes") ? { supervisors: { ...policy.bridge?.supervisors, hermes: { path: join23(dataDir2, "agent-hooks", "hermes.js"), runtime: process.execPath, sha256: sha4(renderHermesSupervisor(bindings.get("hermes").command, bindings.get("hermes").profileId)) } } } : {},
43116
43295
  commands: { ...policy.bridge?.commands, ...Object.fromEntries([...bindings].map(([agent, binding]) => [agent, binding.command])) },
43117
43296
  profiles: Object.fromEntries([...new Set([...priorAgents, ...options.agents])].sort().map((agent) => [agent, bindings.get(agent)?.profileId ?? policy.bridge?.profiles?.[agent] ?? policy.profileId])),
43118
- disabledBuiltins: options.agents.includes("codex") ? nativeSkills.filter((entry) => entry.agent === "codex" && entry.vendor && entry.path.startsWith(canonicalAgentPath(join22(home, ".codex", "skills", ".system"), aliases) + sep5)).map((entry) => ({ path: entry.path, hash: entry.hash })) : policy.bridge?.disabledBuiltins ?? [],
43297
+ disabledBuiltins: options.agents.includes("codex") ? nativeSkills.filter((entry) => entry.agent === "codex" && entry.vendor && entry.path.startsWith(canonicalAgentPath(join23(home, ".codex", "skills", ".system"), aliases) + sep5)).map((entry) => ({ path: entry.path, hash: entry.hash })) : policy.bridge?.disabledBuiltins ?? [],
43119
43298
  rootAliases: aliases,
43120
43299
  ...options.codexNativeCatalog || codexPluginSkills.length || codexInactivePlugins.length || codexPluginSourceInputs.length ? { codexPluginSkills, codexInactivePlugins, codexPluginSkillReview } : {},
43121
43300
  discovery: { ...policy.bridge?.discovery, ...Object.fromEntries(discoveryAfter.map((binding) => [binding.agent, binding])) }
@@ -43138,7 +43317,7 @@ function claudeSettingsConsumers(home, path, discoveries, aliases) {
43138
43317
  const distance = relative4(canonical6(root2), path);
43139
43318
  return distance === "" || distance !== ".." && !distance.startsWith(`..${sep5}`) && !isAbsolute17(distance);
43140
43319
  };
43141
- return discoveries.filter((binding) => binding.agent === "claude" || binding.agent === "opencode" || canonical6(join22(home, AGENT_ADAPTERS[binding.agent].config)) === path || binding.sources.some((source) => canonical6(source.path) === path) || binding.roots.some(containsSettings) || binding.directories?.some((directory) => containsSettings(directory.path))).map((binding) => binding.agent);
43320
+ return discoveries.filter((binding) => binding.agent === "claude" || binding.agent === "opencode" || canonical6(join23(home, AGENT_ADAPTERS[binding.agent].config)) === path || binding.sources.some((source) => canonical6(source.path) === path) || binding.roots.some(containsSettings) || binding.directories?.some((directory) => containsSettings(directory.path))).map((binding) => binding.agent);
43142
43321
  }
43143
43322
  function verifyCoordinatedDiscovery(binding, home, aliases) {
43144
43323
  try {
@@ -43155,8 +43334,8 @@ function verifyCoordinatedDiscovery(binding, home, aliases) {
43155
43334
  }
43156
43335
  }
43157
43336
  function planClaudeHookEventsUpdate(options) {
43158
- const home = resolve15(options.home ?? homedir3()), dataDir2 = options.dataDir ?? getDataDirReadOnly();
43159
- const policyPath = join22(dataDir2, "agent-policy.json");
43337
+ const home = resolve16(options.home ?? homedir3()), dataDir2 = options.dataDir ?? getDataDirReadOnly();
43338
+ const policyPath = join23(dataDir2, "agent-policy.json");
43160
43339
  assertSafePath(policyPath);
43161
43340
  const snapshot2 = readManagedSkillPolicySnapshot(dataDir2);
43162
43341
  if (!snapshot2)
@@ -43167,9 +43346,9 @@ function planClaudeHookEventsUpdate(options) {
43167
43346
  }
43168
43347
  const aliases = bridge.rootAliases ?? [];
43169
43348
  recheckRootAliases(aliases);
43170
- const path = canonicalAgentPath(join22(home, ".claude", "settings.json"), aliases);
43349
+ const path = canonicalAgentPath(join23(home, ".claude", "settings.json"), aliases);
43171
43350
  assertSafePath(path);
43172
- const before = lstatSync19(path, { throwIfNoEntry: false }) ? new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(readNativeBytes(path, 1024 * 1024)) : null;
43351
+ const before = lstatSync20(path, { throwIfNoEntry: false }) ? new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(readNativeBytes(path, 1024 * 1024)) : null;
43173
43352
  if ((before === null ? "absent" : sha4(before)) !== options.expectedSettingsSha256)
43174
43353
  throw new Error("Claude settings preimage changed");
43175
43354
  assertClaudeHookEventsReplacement(before, options.replacement, options.events);
@@ -43229,14 +43408,14 @@ function atomicWrite2(path, content) {
43229
43408
  writeFileSync4(temporary, content, { mode: 384, flag: "wx" });
43230
43409
  renameSync3(temporary, path);
43231
43410
  } finally {
43232
- if (existsSync6(temporary))
43411
+ if (existsSync7(temporary))
43233
43412
  unlinkSync4(temporary);
43234
43413
  }
43235
43414
  }
43236
43415
  function planAgentSettingsWitnessUpgrade(options) {
43237
43416
  if (options.targetCodexVersion !== undefined && (options.agent !== "codex" || ![2, 3].includes(options.targetCodexVersion)))
43238
43417
  throw new Error("Invalid Codex witness target version");
43239
- const home = resolve15(options.home ?? homedir3()), dataDir2 = options.dataDir ?? getDataDirReadOnly();
43418
+ const home = resolve16(options.home ?? homedir3()), dataDir2 = options.dataDir ?? getDataDirReadOnly();
43240
43419
  const snapshot2 = readManagedSkillPolicySnapshot(dataDir2);
43241
43420
  if (!snapshot2 || sha4(snapshot2.text) !== options.expectedPolicySha256)
43242
43421
  throw new Error("Managed policy preimage changed");
@@ -43245,7 +43424,7 @@ function planAgentSettingsWitnessUpgrade(options) {
43245
43424
  const binding = policy.bridge?.discovery?.[options.agent];
43246
43425
  if (!binding || binding.agent !== options.agent || binding.method !== "reviewed")
43247
43426
  throw new Error("Settings witness upgrade requires an existing reviewed native binding");
43248
- const configPath = canonicalAgentPath(join22(home, options.agent === "claude" ? ".claude/settings.json" : ".codex/config.toml"), aliases);
43427
+ const configPath = canonicalAgentPath(join23(home, options.agent === "claude" ? ".claude/settings.json" : ".codex/config.toml"), aliases);
43249
43428
  const settings = readOptional(configPath);
43250
43429
  if (settings === null || sha4(settings) !== options.expectedSettingsSha256)
43251
43430
  throw new Error("Native settings preimage changed");
@@ -43284,7 +43463,7 @@ function planAgentSettingsWitnessUpgrade(options) {
43284
43463
  const replacement = { ...binding, sources: rebound };
43285
43464
  verifyAgentDiscovery(replacement);
43286
43465
  const after = serializeManagedSkillPolicy({ ...policy, bridge: { ...policy.bridge, discovery: { ...policy.bridge.discovery, [options.agent]: replacement } } });
43287
- return { dataDir: dataDir2, profileId: policy.profileId, changes: [{ path: join22(dataDir2, "agent-policy.json"), before: snapshot2.text, after }], nativeSkills: [], observedPolicy: { path: join22(dataDir2, "agent-policy.json"), before: snapshot2.text }, observedSettings: { path: configPath, before: settings }, discoveryBefore: [replacement], discoveryAfter: [replacement], rootAliases: aliases, managedAgentChecks: { home, agents: [options.agent] }, settingsWitnessUpgrade: { agent: options.agent, path: configPath, fromHashMode: previous.hashMode ?? "bytes", fromSha256: previous.sha256, toHashMode: next.hashMode, toSha256: next.sha256, reviewedPreimage: options.reviewedPreimage, currentSettingsSha256: options.expectedSettingsSha256, replacedWitnesses: replaced.map((source) => ({ hashMode: source.hashMode ?? "bytes", sha256: source.sha256 })) } };
43466
+ return { dataDir: dataDir2, profileId: policy.profileId, changes: [{ path: join23(dataDir2, "agent-policy.json"), before: snapshot2.text, after }], nativeSkills: [], observedPolicy: { path: join23(dataDir2, "agent-policy.json"), before: snapshot2.text }, observedSettings: { path: configPath, before: settings }, discoveryBefore: [replacement], discoveryAfter: [replacement], rootAliases: aliases, managedAgentChecks: { home, agents: [options.agent] }, settingsWitnessUpgrade: { agent: options.agent, path: configPath, fromHashMode: previous.hashMode ?? "bytes", fromSha256: previous.sha256, toHashMode: next.hashMode, toSha256: next.sha256, reviewedPreimage: options.reviewedPreimage, currentSettingsSha256: options.expectedSettingsSha256, replacedWitnesses: replaced.map((source) => ({ hashMode: source.hashMode ?? "bytes", sha256: source.sha256 })) } };
43288
43467
  }
43289
43468
  function applyAgentIntegration(plan) {
43290
43469
  for (const source of plan.observedNativeSources ?? [])
@@ -43292,12 +43471,12 @@ function applyAgentIntegration(plan) {
43292
43471
  throw new Error("Native identity source changed after planning");
43293
43472
  if (plan.observedSettings && readOptional(plan.observedSettings.path) !== plan.observedSettings.before)
43294
43473
  throw new Error("Native settings changed after witness planning");
43295
- const policyPath = join22(plan.dataDir, "agent-policy.json");
43474
+ const policyPath = join23(plan.dataDir, "agent-policy.json");
43296
43475
  assertSafePath(policyPath);
43297
- const currentText = (path) => resolve15(path) === resolve15(policyPath) ? readManagedSkillPolicySnapshot(plan.dataDir)?.text ?? null : readOptional(path);
43476
+ const currentText = (path) => resolve16(path) === resolve16(policyPath) ? readManagedSkillPolicySnapshot(plan.dataDir)?.text ?? null : readOptional(path);
43298
43477
  readManagedSkillPolicySnapshot(plan.dataDir);
43299
43478
  for (const change of plan.changes)
43300
- if (resolve15(change.path) === resolve15(policyPath))
43479
+ if (resolve16(change.path) === resolve16(policyPath))
43301
43480
  parseManagedSkillPolicy(change.after);
43302
43481
  const aliases = plan.rootAliases ?? [];
43303
43482
  recheckRootAliases(aliases);
@@ -43326,7 +43505,7 @@ function applyAgentIntegration(plan) {
43326
43505
  for (const change of plan.changes)
43327
43506
  if (currentText(change.path) !== change.before)
43328
43507
  throw new Error(`Configuration changed after planning: ${change.path}`);
43329
- const backupRoot = join22(plan.dataDir, "migration", randomUUID3()), backups = [], written = [], createdDirectories = new Set;
43508
+ const backupRoot = join23(plan.dataDir, "migration", randomUUID3()), backups = [], written = [], createdDirectories = new Set;
43330
43509
  if (!plan.changes.length) {
43331
43510
  recheckRootAliases(aliases);
43332
43511
  return { changed: [], backups, ...aliases.length ? { rootAliases: aliases } : {} };
@@ -43336,7 +43515,7 @@ function applyAgentIntegration(plan) {
43336
43515
  chmodSync(backupRoot, 448);
43337
43516
  for (const [index, change] of plan.changes.entries())
43338
43517
  if (change.before !== null) {
43339
- const backup = join22(backupRoot, `${index}-${sha4(change.path).slice(0, 12)}.backup`);
43518
+ const backup = join23(backupRoot, `${index}-${sha4(change.path).slice(0, 12)}.backup`);
43340
43519
  writeFileSync4(backup, change.before, { mode: 384, flag: "wx" });
43341
43520
  if (readFileSync14(backup, "utf8") !== change.before)
43342
43521
  throw new Error("Native configuration preservation readback failed");
@@ -43347,7 +43526,7 @@ function applyAgentIntegration(plan) {
43347
43526
  recheckRootAliases(aliases);
43348
43527
  if (currentText(change.path) !== change.before)
43349
43528
  throw new Error(`Configuration changed after planning: ${change.path}`);
43350
- for (let directory = dirname15(change.path);!existsSync6(directory); directory = dirname15(directory))
43529
+ for (let directory = dirname15(change.path);!existsSync7(directory); directory = dirname15(directory))
43351
43530
  createdDirectories.add(directory);
43352
43531
  const after = change.after;
43353
43532
  atomicWrite2(change.path, after);
@@ -43367,7 +43546,7 @@ function applyAgentIntegration(plan) {
43367
43546
  }
43368
43547
  for (const agent of plan.managedAgentChecks?.agents ?? [])
43369
43548
  assertManagedAgentBridge(agent, { home: plan.managedAgentChecks.home, dataDir: plan.dataDir, projectDir: plan.managedAgentChecks.home });
43370
- atomicWrite2(join22(backupRoot, "receipt.json"), JSON.stringify({ version: 1, changes: written.map((change) => ({ path: change.path, beforeHash: change.before === null ? null : sha4(change.before), afterHash: sha4(change.after) })), backups, ...aliases.length ? { rootAliases: aliases } : {} }) + `
43549
+ atomicWrite2(join23(backupRoot, "receipt.json"), JSON.stringify({ version: 1, changes: written.map((change) => ({ path: change.path, beforeHash: change.before === null ? null : sha4(change.before), afterHash: sha4(change.after) })), backups, ...aliases.length ? { rootAliases: aliases } : {} }) + `
43371
43550
  `);
43372
43551
  } catch (error) {
43373
43552
  for (const change of written.reverse()) {
@@ -43421,7 +43600,7 @@ function writeArchiveJournal(path, value) {
43421
43600
  } finally {
43422
43601
  if (descriptor !== undefined)
43423
43602
  closeSync16(descriptor);
43424
- if (lstatSync19(temporary, { throwIfNoEntry: false }))
43603
+ if (lstatSync20(temporary, { throwIfNoEntry: false }))
43425
43604
  unlinkSync4(temporary);
43426
43605
  }
43427
43606
  }
@@ -43432,7 +43611,7 @@ function archiveNativeSkills(inventory, options) {
43432
43611
  recheckRootAliases(aliases);
43433
43612
  for (const entry of inventory.filter((entry2) => entry2.bridge)) {
43434
43613
  const adapter = AGENT_ADAPTERS[entry.agent];
43435
- const expected = adapter && entry.bridgeHome ? canonicalAgentPath(join22(entry.bridgeHome, adapter.root, CLI_BRIDGE_NAME), aliases) : undefined;
43614
+ const expected = adapter && entry.bridgeHome ? canonicalAgentPath(join23(entry.agent === "sumi" ? sumiBridgeRoot(entry.bridgeHome) : join23(entry.bridgeHome, adapter.root), CLI_BRIDGE_NAME), aliases) : undefined;
43436
43615
  if (!expected || treeHash(entry.path) !== entry.hash || !isOwnedCliBridge(entry.path, [expected]))
43437
43616
  throw new Error(`Skills bridge changed after planning: ${entry.path}`);
43438
43617
  }
@@ -43443,11 +43622,11 @@ function archiveNativeSkills(inventory, options) {
43443
43622
  const targetManifest = options.targetManifest ? { schema: options.targetManifest.schema, digest: options.targetManifest.digest, targetCount: options.targetManifest.targets.length } : undefined;
43444
43623
  if (!selected.length)
43445
43624
  return { entries: [], ...targetManifest ? { targetManifest } : {}, ...aliases.length ? { rootAliases: aliases } : {} };
43446
- const operationId = randomUUID3(), archiveRoot = join22(options.dataDir ?? getDataDir(), "migration", operationId, "native"), receiptPath = join22(archiveRoot, "receipt.json");
43625
+ const operationId = randomUUID3(), archiveRoot = join23(options.dataDir ?? getDataDir(), "migration", operationId, "native"), receiptPath = join23(archiveRoot, "receipt.json");
43447
43626
  const entries = selected.map((entry, index) => ({
43448
- source: entry.vendor ? join22(entry.path, "SKILL.md") : entry.path,
43449
- archive: join22(archiveRoot, `${index}-${sha4(entry.path).slice(0, 12)}`),
43450
- hash: entry.vendor ? sha4(readNativeBytes(join22(entry.path, "SKILL.md"))) : entry.hash,
43627
+ source: entry.vendor ? join23(entry.path, "SKILL.md") : entry.path,
43628
+ archive: join23(archiveRoot, `${index}-${sha4(entry.path).slice(0, 12)}`),
43629
+ hash: entry.vendor ? sha4(readNativeBytes(join23(entry.path, "SKILL.md"))) : entry.hash,
43451
43630
  ...entry.vendor ? { discoveryOnly: true } : {},
43452
43631
  status: "planned"
43453
43632
  }));
@@ -43455,7 +43634,7 @@ function archiveNativeSkills(inventory, options) {
43455
43634
  const moved = [];
43456
43635
  const verifyArchive = (entry) => {
43457
43636
  assertSafePath(entry.archive);
43458
- const stat2 = lstatSync19(entry.archive);
43637
+ const stat2 = lstatSync20(entry.archive);
43459
43638
  if (entry.discoveryOnly ? !stat2.isFile() : !stat2.isDirectory())
43460
43639
  throw new Error("Archive type changed");
43461
43640
  if ((entry.discoveryOnly ? sha4(readNativeBytes(entry.archive)) : treeHash(entry.archive)) !== entry.hash)
@@ -43463,7 +43642,7 @@ function archiveNativeSkills(inventory, options) {
43463
43642
  };
43464
43643
  assertSafePath(archiveRoot);
43465
43644
  const created = [];
43466
- for (let path = archiveRoot;!existsSync6(path); path = dirname15(path))
43645
+ for (let path = archiveRoot;!existsSync7(path); path = dirname15(path))
43467
43646
  created.push(path);
43468
43647
  mkdirSync5(archiveRoot, { recursive: true, mode: 448 });
43469
43648
  try {
@@ -43503,7 +43682,7 @@ function archiveNativeSkills(inventory, options) {
43503
43682
  recheckRootAliases(aliases);
43504
43683
  assertSafePath(entry.source);
43505
43684
  assertSafePath(entry.archive);
43506
- if (lstatSync19(entry.source, { throwIfNoEntry: false })) {
43685
+ if (lstatSync20(entry.source, { throwIfNoEntry: false })) {
43507
43686
  entry.status = "recovery-required";
43508
43687
  entry.conflict = "source-occupied";
43509
43688
  continue;
@@ -43520,7 +43699,7 @@ function archiveNativeSkills(inventory, options) {
43520
43699
  syncArchiveDirectory(dirname15(entry.source));
43521
43700
  unlinkSync4(entry.archive);
43522
43701
  } else {
43523
- if (lstatSync19(entry.source, { throwIfNoEntry: false })) {
43702
+ if (lstatSync20(entry.source, { throwIfNoEntry: false })) {
43524
43703
  entry.status = "recovery-required";
43525
43704
  entry.conflict = "source-occupied";
43526
43705
  continue;
@@ -43551,8 +43730,8 @@ function assertManagedAgentBridge(agent, options = {}) {
43551
43730
  assertManagedAgentBridgeWithDiscovery(agent, options);
43552
43731
  }
43553
43732
  function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscovery) {
43554
- const home = resolve15(options.home ?? homedir3()), dataDir2 = options.dataDir ?? getDataDirReadOnly();
43555
- assertSafePath(join22(dataDir2, "agent-policy.json"));
43733
+ const home = resolve16(options.home ?? homedir3()), dataDir2 = options.dataDir ?? getDataDirReadOnly();
43734
+ assertSafePath(join23(dataDir2, "agent-policy.json"));
43556
43735
  const snapshot2 = readManagedSkillPolicySnapshot(dataDir2);
43557
43736
  if (!snapshot2)
43558
43737
  throw new Error("NATIVE_SKILL_DRIFT: install the Skills bridge with skills hook install");
@@ -43563,14 +43742,14 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
43563
43742
  if (!Array.isArray(aliases))
43564
43743
  throw new Error("NATIVE_SKILL_DRIFT: invalid root alias binding");
43565
43744
  recheckRootAliases(aliases);
43566
- const expected = canonicalAgentPath(join22(home, AGENT_ADAPTERS[agent].root, CLI_BRIDGE_NAME), aliases);
43745
+ const expected = canonicalAgentPath(join23(agent === "sumi" ? sumiBridgeRoot(home) : join23(home, AGENT_ADAPTERS[agent].root), CLI_BRIDGE_NAME), aliases);
43567
43746
  if (!isOwnedCliBridge(expected, [expected]))
43568
43747
  throw new Error("NATIVE_SKILL_DRIFT: the native Skills bridge is missing or modified; repair it before continuing");
43569
43748
  const roots = projectAncestorDirectories([options.projectDir ?? process.cwd(), ...options.projectDirs ?? [], ...agent === "hermes" && process.env.TERMINAL_CWD ? [process.cwd()] : []]);
43570
- const visible = (entry) => entry.agent === agent || ["codex", "gemini", "opencode", "hermes"].includes(agent) && entry.path.includes(`${sep5}.agents${sep5}skills${sep5}`) || agent === "opencode" && entry.agent === "claude";
43749
+ const visible = (entry) => entry.agent === agent || ["codex", "gemini", "opencode", "hermes", "sumi"].includes(agent) && entry.path.includes(`${sep5}.agents${sep5}skills${sep5}`) || ["opencode", "sumi"].includes(agent) && entry.agent === "claude";
43571
43750
  const discovery = provenDiscovery ?? binding.discovery?.[agent];
43572
43751
  assertProjectDiscovery(agent, [...roots], home, (path) => canonicalAgentPath(path, aliases), discovery);
43573
- const configPath = canonicalAgentPath(join22(home, AGENT_ADAPTERS[agent].config), aliases), config = agent === "hermes" ? parseHermesConfig(readOptional(configPath)) : jsonObject(readOptional(configPath), configPath);
43752
+ const configPath = canonicalAgentPath(agent === "sumi" ? sumiConfigPath(home) : join23(home, AGENT_ADAPTERS[agent].config), aliases), config = agent === "hermes" ? parseHermesConfig(readOptional(configPath)) : jsonObject(readOptional(configPath), configPath);
43574
43753
  const command = binding.commands?.[agent], profile = binding.profiles?.[agent];
43575
43754
  if (typeof command !== "string" || typeof profile !== "string")
43576
43755
  throw new Error("NATIVE_SKILL_DRIFT: the native hook command/profile binding is missing");
@@ -43578,11 +43757,14 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
43578
43757
  throw new Error("NATIVE_SKILL_DRIFT: the hook selection profile differs from its managed binding; restart the native client after reviewing skills hook install");
43579
43758
  if (agent === "hermes") {
43580
43759
  const supervisor = binding.supervisors?.hermes;
43581
- if (supervisor?.path !== join22(dataDir2, "agent-hooks", "hermes.js") || supervisor?.sha256 !== sha4(renderHermesSupervisor(command, profile)))
43760
+ if (supervisor?.path !== join23(dataDir2, "agent-hooks", "hermes.js") || supervisor?.sha256 !== sha4(renderHermesSupervisor(command, profile)))
43582
43761
  throw new Error("NATIVE_SKILL_DRIFT: Hermes supervisor binding changed; run skills hook install");
43583
43762
  assertHermesProtection(home, config, command, profile, supervisor);
43763
+ } else if (agent === "sumi") {
43764
+ if (JSON.stringify(config.permissions?.filter((rule) => rule.action === "skill")) !== JSON.stringify(SUMI_SKILL_PERMISSIONS) || readOptional(join23(sumiConfigDirectory(home), "plugins", "skills-cli.js")) !== renderSumiPlugin(command, profile))
43765
+ throw new Error("NATIVE_SKILL_DRIFT: Sumi bridge protection changed; run skills hook install");
43584
43766
  } else if (agent === "opencode") {
43585
- if (JSON.stringify(config.permission?.skill) !== JSON.stringify({ "*": "deny", [CLI_BRIDGE_NAME]: "allow" }) || readOptional(join22(home, ".config", "opencode", "plugins", "skills-cli.js")) !== renderOpenCodePlugin(command, profile))
43767
+ if (JSON.stringify(config.permission?.skill) !== JSON.stringify({ "*": "deny", [CLI_BRIDGE_NAME]: "allow" }) || readOptional(join23(home, ".config", "opencode", "plugins", "skills-cli.js")) !== renderOpenCodePlugin(command, profile))
43586
43768
  throw new Error("NATIVE_SKILL_DRIFT: OpenCode bridge protection changed; run skills hook install");
43587
43769
  } else {
43588
43770
  const required = {};
@@ -43599,21 +43781,21 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
43599
43781
  if (agent === "gemini" && (config.hooksConfig?.enabled === false || config.skills?.enabled !== true || !["antigravity-support", "skill-creator"].every((name) => config.skills?.disabled?.includes(name)) || config.skills?.disabled?.includes(CLI_BRIDGE_NAME)))
43600
43782
  throw new Error("NATIVE_SKILL_DRIFT: Gemini bridge or bundled-skill protection changed; run skills hook install");
43601
43783
  }
43602
- const codexPath = canonicalAgentPath(join22(home, ".codex", "config.toml"), aliases);
43784
+ const codexPath = canonicalAgentPath(join23(home, ".codex", "config.toml"), aliases);
43603
43785
  if (options.codexDiscoveryRecovery && (agent !== "codex" || options.codexDiscoveryRecovery.configPath !== codexPath))
43604
43786
  throw new Error("NATIVE_SKILL_DRIFT: Codex trust recovery names a different configuration root");
43605
43787
  const codexConfig = agent === "codex" ? Bun.TOML.parse(readOptional(codexPath) ?? "") : {};
43606
43788
  if (agent === "codex" && codexConfig.skills?.bundled?.enabled !== false)
43607
43789
  throw new Error("NATIVE_SKILL_DRIFT: Codex bundled skill reseeding is not disabled (skills.bundled.enabled); run skills hook install");
43608
- const setting = (path) => (codexConfig.skills?.config ?? []).filter((entry) => typeof entry.path === "string" && [path, join22(path, "SKILL.md")].includes(canonicalAgentPath(entry.path, aliases)));
43790
+ const setting = (path) => (codexConfig.skills?.config ?? []).filter((entry) => typeof entry.path === "string" && [path, join23(path, "SKILL.md")].includes(canonicalAgentPath(entry.path, aliases)));
43609
43791
  if (agent === "codex" && [...setting(expected), ...(codexConfig.skills?.config ?? []).filter((entry) => typeof entry.name === "string" && entry.name.trim() === CLI_BRIDGE_NAME)].some((entry) => entry.enabled === false))
43610
43792
  throw new Error("NATIVE_SKILL_DRIFT: the Codex CLI bridge is disabled; run skills hook install");
43611
- if (agent === "codex" && !reviewedCodexPluginCapabilitiesUnchanged(canonicalAgentPath(join22(home, ".codex/plugins/cache"), aliases), binding.codexPluginSkills ?? [], (path) => new TextDecoder("utf-8", { fatal: true }).decode(readNativeBytes(path, 1024 * 1024))))
43793
+ if (agent === "codex" && !reviewedCodexPluginCapabilitiesUnchanged(canonicalAgentPath(join23(home, ".codex/plugins/cache"), aliases), binding.codexPluginSkills ?? [], (path) => new TextDecoder("utf-8", { fatal: true }).decode(readNativeBytes(path, 1024 * 1024))))
43612
43794
  throw new Error("NATIVE_SKILL_DRIFT: reviewed native plugin capability controls changed; run skills hook install with a fresh discovery review");
43613
43795
  const disabledPlugin = (entry) => {
43614
43796
  if (agent !== "codex" || !entry.vendor)
43615
43797
  return false;
43616
- const document2 = join22(entry.path, "SKILL.md"), cache = canonicalAgentPath(join22(home, ".codex/plugins/cache"), aliases), read3 = (path) => new TextDecoder("utf-8", { fatal: true }).decode(readNativeBytes(path, 1024 * 1024));
43798
+ const document2 = join23(entry.path, "SKILL.md"), cache = canonicalAgentPath(join23(home, ".codex/plugins/cache"), aliases), read3 = (path) => new TextDecoder("utf-8", { fatal: true }).decode(readNativeBytes(path, 1024 * 1024));
43617
43799
  return isReviewedCodexPluginInactive(document2, cache, binding.codexInactivePlugins ?? [], codexConfig.plugins, codexConfig.skills?.config ?? [], read3) || isReviewedCodexPluginSkillDisabled(document2, cache, binding.codexPluginSkills ?? [], codexConfig.skills?.config, read3);
43618
43800
  };
43619
43801
  const disabledPaths = new Set(disabledCodexSkillPaths(codexConfig, aliases));
@@ -43626,15 +43808,15 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
43626
43808
  return true;
43627
43809
  if (!disabledPaths.has(entry.path))
43628
43810
  return false;
43629
- if (entry.path.startsWith(canonicalAgentPath(join22(home, ".codex", "plugins", "cache"), aliases) + sep5))
43811
+ if (entry.path.startsWith(canonicalAgentPath(join23(home, ".codex", "plugins", "cache"), aliases) + sep5))
43630
43812
  return true;
43631
- const runtimeCache = canonicalAgentPath(join22(home, ".cache", "codex-runtimes"), aliases);
43813
+ const runtimeCache = canonicalAgentPath(join23(home, ".cache", "codex-runtimes"), aliases);
43632
43814
  if (entry.path.startsWith(runtimeCache + sep5) && discovery?.method === "automatic" && discovery.roots.some((root2) => entry.path.startsWith(root2 + sep5)))
43633
43815
  return true;
43634
- const bundledMarketplaces = canonicalAgentPath(join22(home, ".codex", ".tmp", "bundled-marketplaces"), aliases);
43816
+ const bundledMarketplaces = canonicalAgentPath(join23(home, ".codex", ".tmp", "bundled-marketplaces"), aliases);
43635
43817
  if (entry.path.startsWith(bundledMarketplaces + sep5) && discovery?.method === "automatic" && discovery.roots.some((root2) => entry.path.startsWith(root2 + sep5)))
43636
43818
  return true;
43637
- if (!entry.path.startsWith(canonicalAgentPath(join22(home, ".codex", "skills", ".system"), aliases) + sep5))
43819
+ if (!entry.path.startsWith(canonicalAgentPath(join23(home, ".codex", "skills", ".system"), aliases) + sep5))
43638
43820
  return false;
43639
43821
  return Array.isArray(binding.disabledBuiltins) && binding.disabledBuiltins.some((item) => item.path === entry.path && item.hash === entry.hash);
43640
43822
  };
@@ -43644,6 +43826,8 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
43644
43826
  throw new Error("NATIVE_SKILL_DRIFT: an installed Gemini builtin is not disabled");
43645
43827
  try {
43646
43828
  verifyAgentDiscovery(discovery, options.codexDiscoveryRecovery);
43829
+ if (agent === "sumi" && discovery.method === "reviewed")
43830
+ resolveAgentDiscovery({ home, agent, retainedReview: discovery, canonical: (path) => canonicalAgentPath(path, aliases) });
43647
43831
  if (discovery.method === "automatic") {
43648
43832
  const current = resolveAgentDiscovery({ home, agent, canonical: (path) => canonicalAgentPath(path, aliases) });
43649
43833
  if (JSON.stringify(current) !== JSON.stringify(discovery))
@@ -43655,7 +43839,7 @@ function assertManagedAgentBridgeWithDiscovery(agent, options = {}, provenDiscov
43655
43839
  let installationInputRoots = [];
43656
43840
  if (agent === "codex") {
43657
43841
  try {
43658
- installationInputRoots = reviewedCodexPluginSourceRoots(canonicalAgentPath(join22(home, ".codex/plugins/cache"), aliases), discovery.codexInstallationInputs?.plugins ?? [], (path) => new TextDecoder("utf-8", { fatal: true }).decode(readNativeBytes(path, 1024 * 1024)));
43842
+ installationInputRoots = reviewedCodexPluginSourceRoots(canonicalAgentPath(join23(home, ".codex/plugins/cache"), aliases), discovery.codexInstallationInputs?.plugins ?? [], (path) => new TextDecoder("utf-8", { fatal: true }).decode(readNativeBytes(path, 1024 * 1024)));
43659
43843
  } catch {
43660
43844
  throw new Error("NATIVE_SKILL_DRIFT: native installation input identity changed; review discovery and catalog");
43661
43845
  }
@@ -43679,25 +43863,25 @@ function assertNativeExportAllowed(dataDir2 = getDataDirReadOnly()) {
43679
43863
 
43680
43864
  // src/lib/portable-skills.ts
43681
43865
  import {
43682
- existsSync as existsSync9,
43866
+ existsSync as existsSync10,
43683
43867
  mkdirSync as mkdirSync7,
43684
43868
  mkdtempSync,
43685
43869
  readdirSync as readdirSync10,
43686
- realpathSync as realpathSync10,
43870
+ realpathSync as realpathSync11,
43687
43871
  renameSync as renameSync4,
43688
43872
  rmSync as rmSync2,
43689
43873
  statSync as statSync9,
43690
43874
  writeFileSync as writeFileSync6
43691
43875
  } from "fs";
43692
- import { basename as basename10, dirname as dirname18, isAbsolute as isAbsolute18, join as join26, normalize as normalize4, relative as relative6, resolve as resolve17, sep as sep8 } from "path";
43876
+ import { basename as basename10, dirname as dirname18, isAbsolute as isAbsolute18, join as join27, normalize as normalize4, relative as relative6, resolve as resolve18, sep as sep8 } from "path";
43693
43877
 
43694
43878
  // src/lib/registry-data/index.ts
43695
43879
  var SKILLS = [];
43696
43880
 
43697
43881
  // src/lib/skill-hash.ts
43698
43882
  import { createHash as createHash19 } from "crypto";
43699
- import { existsSync as existsSync7, readdirSync as readdirSync9, readFileSync as readFileSync15, statSync as statSync7 } from "fs";
43700
- import { join as join23, sep as sep6 } from "path";
43883
+ import { existsSync as existsSync8, readdirSync as readdirSync9, readFileSync as readFileSync15, statSync as statSync7 } from "fs";
43884
+ import { join as join24, sep as sep6 } from "path";
43701
43885
  var CONTENT_HASH_ALGORITHM = "sha256";
43702
43886
  var HASH_EXCLUDE_DIRS = new Set([".git", "node_modules", "dist", "build", ".turbo"]);
43703
43887
  function excludedHashEntry(name, directory) {
@@ -43759,8 +43943,8 @@ function collectBundleFiles(skillPath) {
43759
43943
  if (seen.has(entry))
43760
43944
  continue;
43761
43945
  seen.add(entry);
43762
- const absolute = join23(skillPath, entry);
43763
- if (!existsSync7(absolute))
43946
+ const absolute = join24(skillPath, entry);
43947
+ if (!existsSync8(absolute))
43764
43948
  continue;
43765
43949
  if (statSync7(absolute).isDirectory())
43766
43950
  collectDirectory(files, absolute, entry);
@@ -43773,7 +43957,7 @@ function collectDirectory(files, dir, rel) {
43773
43957
  for (const entry of readdirSync9(dir).sort()) {
43774
43958
  if (entry.startsWith("."))
43775
43959
  continue;
43776
- const absolute = join23(dir, entry);
43960
+ const absolute = join24(dir, entry);
43777
43961
  const childRel = `${rel}/${entry}`;
43778
43962
  let stats;
43779
43963
  try {
@@ -43834,7 +44018,7 @@ async function hashBundleFilesCooperatively(files, check) {
43834
44018
  hash2.update(chunk);
43835
44019
  bytesSinceYield += chunk.byteLength;
43836
44020
  if (bytesSinceYield >= 256 * 1024) {
43837
- await new Promise((resolve16) => setImmediate(resolve16));
44021
+ await new Promise((resolve17) => setImmediate(resolve17));
43838
44022
  bytesSinceYield = 0;
43839
44023
  }
43840
44024
  }
@@ -43987,7 +44171,7 @@ async function hashContentEntries(entries, options) {
43987
44171
  const normalized = [];
43988
44172
  let normalizedBytes = 0;
43989
44173
  let manifest;
43990
- await new Promise((resolve16) => setImmediate(resolve16));
44174
+ await new Promise((resolve17) => setImmediate(resolve17));
43991
44175
  for (const entry of snapshot2) {
43992
44176
  check();
43993
44177
  if (!coveredContentPath(entry.path))
@@ -44000,7 +44184,7 @@ async function hashContentEntries(entries, options) {
44000
44184
  contentLimit("Content hash normalized byte limit exceeded");
44001
44185
  normalizedBytes += file.content.byteLength;
44002
44186
  normalized.push(file);
44003
- await new Promise((resolve16) => setImmediate(resolve16));
44187
+ await new Promise((resolve17) => setImmediate(resolve17));
44004
44188
  }
44005
44189
  normalized.sort((a, b) => a.rel < b.rel ? -1 : a.rel > b.rel ? 1 : 0);
44006
44190
  check();
@@ -44207,14 +44391,14 @@ function validateRuntimeContract(manifest, issues, strict) {
44207
44391
  // src/lib/portable-skills-files.ts
44208
44392
  import {
44209
44393
  cpSync,
44210
- existsSync as existsSync8,
44211
- lstatSync as lstatSync20,
44394
+ existsSync as existsSync9,
44395
+ lstatSync as lstatSync21,
44212
44396
  mkdirSync as mkdirSync6,
44213
44397
  readFileSync as readFileSync16,
44214
- realpathSync as realpathSync8,
44398
+ realpathSync as realpathSync9,
44215
44399
  writeFileSync as writeFileSync5
44216
44400
  } from "fs";
44217
- import { basename as basename8, dirname as dirname16, join as join24, relative as relative5 } from "path";
44401
+ import { basename as basename8, dirname as dirname16, join as join25, relative as relative5 } from "path";
44218
44402
  var ANY_SEGMENT_COPY_EXCLUDES = new Set([
44219
44403
  ".git",
44220
44404
  ".DS_Store",
@@ -44271,12 +44455,12 @@ function readPortableSkillManifestForImport(skillPath) {
44271
44455
  return readManifest(skillPath, basename8(skillPath), normalizeNewPortableSkillName);
44272
44456
  }
44273
44457
  function readManifest(skillPath, fallbackName, normalizeName) {
44274
- const skillJsonPath = join24(skillPath, "skill.json");
44275
- const skillMdPath = join24(skillPath, "SKILL.md");
44276
- const pkgPath = join24(skillPath, "package.json");
44277
- const jsonManifest = existsSync8(skillJsonPath) ? readJsonObject(skillJsonPath) : undefined;
44278
- const frontmatter = existsSync8(skillMdPath) ? parseSkillFrontmatter(readFileSync16(skillMdPath, "utf-8")) ?? undefined : undefined;
44279
- const pkg = existsSync8(pkgPath) ? readJsonObject(pkgPath) : undefined;
44458
+ const skillJsonPath = join25(skillPath, "skill.json");
44459
+ const skillMdPath = join25(skillPath, "SKILL.md");
44460
+ const pkgPath = join25(skillPath, "package.json");
44461
+ const jsonManifest = existsSync9(skillJsonPath) ? readJsonObject(skillJsonPath) : undefined;
44462
+ const frontmatter = existsSync9(skillMdPath) ? parseSkillFrontmatter(readFileSync16(skillMdPath, "utf-8")) ?? undefined : undefined;
44463
+ const pkg = existsSync9(pkgPath) ? readJsonObject(pkgPath) : undefined;
44280
44464
  const name = normalizeName(stringField(jsonManifest, "name") ?? frontmatter?.name ?? stringValue(pkg?.name) ?? fallbackName);
44281
44465
  const description = stringField(jsonManifest, "description") ?? frontmatter?.description ?? stringValue(pkg?.description) ?? `${name} skill`;
44282
44466
  const version = readDeclaredSkillVersion(skillPath) ?? PORTABLE_SKILL_DEFAULT_VERSION;
@@ -44305,12 +44489,12 @@ function parseSkillKind(value) {
44305
44489
  return;
44306
44490
  }
44307
44491
  function readDeclaredSkillVersion(skillPath) {
44308
- const skillJsonPath = join24(skillPath, "skill.json");
44309
- const skillMdPath = join24(skillPath, "SKILL.md");
44310
- const pkgPath = join24(skillPath, "package.json");
44311
- const jsonManifest = existsSync8(skillJsonPath) ? readJsonObject(skillJsonPath) : undefined;
44312
- const frontmatter = existsSync8(skillMdPath) ? parseSkillFrontmatter(readFileSync16(skillMdPath, "utf-8")) ?? undefined : undefined;
44313
- const pkg = existsSync8(pkgPath) ? readJsonObject(pkgPath) : undefined;
44492
+ const skillJsonPath = join25(skillPath, "skill.json");
44493
+ const skillMdPath = join25(skillPath, "SKILL.md");
44494
+ const pkgPath = join25(skillPath, "package.json");
44495
+ const jsonManifest = existsSync9(skillJsonPath) ? readJsonObject(skillJsonPath) : undefined;
44496
+ const frontmatter = existsSync9(skillMdPath) ? parseSkillFrontmatter(readFileSync16(skillMdPath, "utf-8")) ?? undefined : undefined;
44497
+ const pkg = existsSync9(pkgPath) ? readJsonObject(pkgPath) : undefined;
44314
44498
  return stringField(jsonManifest, "version") ?? frontmatter?.version ?? stringValue(pkg?.version);
44315
44499
  }
44316
44500
  function createInstructionManifest(name, options) {
@@ -44331,7 +44515,7 @@ function createInstructionManifest(name, options) {
44331
44515
  }
44332
44516
  function writeInstructionSkillTemplate(skillPath, manifest) {
44333
44517
  mkdirSync6(skillPath, { recursive: true });
44334
- writeFileSync5(join24(skillPath, "SKILL.md"), renderInstructionSkillMd(manifest));
44518
+ writeFileSync5(join25(skillPath, "SKILL.md"), renderInstructionSkillMd(manifest));
44335
44519
  writeSkillJsonWithHash(skillPath, manifest);
44336
44520
  }
44337
44521
  function renderInstructionSkillMd(manifest) {
@@ -44381,12 +44565,12 @@ function createPortableManifest(name, options) {
44381
44565
  };
44382
44566
  }
44383
44567
  function writePortableSkillTemplate(skillPath, manifest) {
44384
- mkdirSync6(join24(skillPath, "src"), { recursive: true });
44385
- writeFileSync5(join24(skillPath, "SKILL.md"), renderSkillMd(manifest));
44386
- writeFileSync5(join24(skillPath, "AGENTS.md"), renderAgentsMd(manifest));
44387
- writeFileSync5(join24(skillPath, "package.json"), renderPackageJson(manifest));
44388
- writeFileSync5(join24(skillPath, "tsconfig.json"), renderTsconfig());
44389
- writeFileSync5(join24(skillPath, "src", "index.ts"), renderEntrypoint(manifest));
44568
+ mkdirSync6(join25(skillPath, "src"), { recursive: true });
44569
+ writeFileSync5(join25(skillPath, "SKILL.md"), renderSkillMd(manifest));
44570
+ writeFileSync5(join25(skillPath, "AGENTS.md"), renderAgentsMd(manifest));
44571
+ writeFileSync5(join25(skillPath, "package.json"), renderPackageJson(manifest));
44572
+ writeFileSync5(join25(skillPath, "tsconfig.json"), renderTsconfig());
44573
+ writeFileSync5(join25(skillPath, "src", "index.ts"), renderEntrypoint(manifest));
44390
44574
  writeSkillJsonWithHash(skillPath, manifest);
44391
44575
  }
44392
44576
  function fillContractDefaults(manifest, entrypoint) {
@@ -44411,7 +44595,7 @@ function writeSkillJsonWithHash(skillPath, manifest) {
44411
44595
  content_hash: undefined
44412
44596
  }
44413
44597
  };
44414
- writeFileSync5(join24(skillPath, "skill.json"), `${JSON.stringify({ ...existing, ...renderSkillJsonObject(withoutHash) }, null, 2)}
44598
+ writeFileSync5(join25(skillPath, "skill.json"), `${JSON.stringify({ ...existing, ...renderSkillJsonObject(withoutHash) }, null, 2)}
44415
44599
  `);
44416
44600
  const hash2 = computeContentHash(skillPath);
44417
44601
  const withHash = {
@@ -44421,13 +44605,13 @@ function writeSkillJsonWithHash(skillPath, manifest) {
44421
44605
  content_hash: hash2
44422
44606
  }
44423
44607
  };
44424
- writeFileSync5(join24(skillPath, "skill.json"), `${JSON.stringify({ ...existing, ...renderSkillJsonObject(withHash) }, null, 2)}
44608
+ writeFileSync5(join25(skillPath, "skill.json"), `${JSON.stringify({ ...existing, ...renderSkillJsonObject(withHash) }, null, 2)}
44425
44609
  `);
44426
44610
  return withHash;
44427
44611
  }
44428
44612
  function readExistingSkillJson(skillPath) {
44429
- const path = join24(skillPath, "skill.json");
44430
- if (!existsSync8(path))
44613
+ const path = join25(skillPath, "skill.json");
44614
+ if (!existsSync9(path))
44431
44615
  return {};
44432
44616
  try {
44433
44617
  const parsed = JSON.parse(readFileSync16(path, "utf-8"));
@@ -44460,28 +44644,28 @@ function ensurePortableSkillFiles(skillPath, manifest) {
44460
44644
  tags: next.tags?.length ? next.tags : ["custom", next.name]
44461
44645
  };
44462
44646
  const entry = next.commands[0]?.entry ?? "src/index.ts";
44463
- if (entry && !existsSync8(join24(skillPath, entry))) {
44464
- mkdirSync6(dirname16(join24(skillPath, entry)), { recursive: true });
44465
- writeFileSync5(join24(skillPath, entry), renderEntrypoint(next));
44647
+ if (entry && !existsSync9(join25(skillPath, entry))) {
44648
+ mkdirSync6(dirname16(join25(skillPath, entry)), { recursive: true });
44649
+ writeFileSync5(join25(skillPath, entry), renderEntrypoint(next));
44466
44650
  }
44467
- if (!existsSync8(join24(skillPath, "SKILL.md")))
44468
- writeFileSync5(join24(skillPath, "SKILL.md"), renderSkillMd(next));
44651
+ if (!existsSync9(join25(skillPath, "SKILL.md")))
44652
+ writeFileSync5(join25(skillPath, "SKILL.md"), renderSkillMd(next));
44469
44653
  else
44470
- writeFileSync5(join24(skillPath, "SKILL.md"), ensureSkillMdFrontmatter(readFileSync16(join24(skillPath, "SKILL.md"), "utf-8"), next));
44471
- if (!existsSync8(join24(skillPath, "AGENTS.md")))
44472
- writeFileSync5(join24(skillPath, "AGENTS.md"), renderAgentsMd(next));
44654
+ writeFileSync5(join25(skillPath, "SKILL.md"), ensureSkillMdFrontmatter(readFileSync16(join25(skillPath, "SKILL.md"), "utf-8"), next));
44655
+ if (!existsSync9(join25(skillPath, "AGENTS.md")))
44656
+ writeFileSync5(join25(skillPath, "AGENTS.md"), renderAgentsMd(next));
44473
44657
  ensurePackageJson(skillPath, next);
44474
- if (!existsSync8(join24(skillPath, "tsconfig.json")))
44475
- writeFileSync5(join24(skillPath, "tsconfig.json"), renderTsconfig());
44658
+ if (!existsSync9(join25(skillPath, "tsconfig.json")))
44659
+ writeFileSync5(join25(skillPath, "tsconfig.json"), renderTsconfig());
44476
44660
  writeSkillJsonWithHash(skillPath, next);
44477
44661
  return readPortableSkillManifest(skillPath, next.name);
44478
44662
  }
44479
44663
  function ensurePackageJson(skillPath, manifest) {
44480
- const pkgPath = join24(skillPath, "package.json");
44664
+ const pkgPath = join25(skillPath, "package.json");
44481
44665
  const first = manifest.commands[0] ?? { name: manifest.name, entry: "src/index.ts" };
44482
44666
  const commandName = normalizePortableSkillName(first.name || manifest.name);
44483
44667
  const entry = (first.entry ?? "src/index.ts").replace(/^\.\//, "");
44484
- if (!existsSync8(pkgPath)) {
44668
+ if (!existsSync9(pkgPath)) {
44485
44669
  writeFileSync5(pkgPath, renderPackageJson(manifest));
44486
44670
  return;
44487
44671
  }
@@ -44524,18 +44708,18 @@ function ensureInstructionSkillFiles(skillPath, manifest) {
44524
44708
  inputs: [],
44525
44709
  commands: []
44526
44710
  };
44527
- if (!existsSync8(join24(skillPath, "SKILL.md"))) {
44528
- writeFileSync5(join24(skillPath, "SKILL.md"), renderSkillMd(next));
44711
+ if (!existsSync9(join25(skillPath, "SKILL.md"))) {
44712
+ writeFileSync5(join25(skillPath, "SKILL.md"), renderSkillMd(next));
44529
44713
  } else {
44530
- const path = join24(skillPath, "SKILL.md");
44714
+ const path = join25(skillPath, "SKILL.md");
44531
44715
  const content = readFileSync16(path, "utf8");
44532
44716
  const declaredName = parseSkillFrontmatter(content)?.name;
44533
44717
  if (declaredName && declaredName !== next.name) {
44534
44718
  writeFileSync5(path, renameInstructionFrontmatter(content, next.name));
44535
44719
  }
44536
44720
  }
44537
- const packagePath = join24(skillPath, "package.json");
44538
- if (existsSync8(packagePath)) {
44721
+ const packagePath = join25(skillPath, "package.json");
44722
+ if (existsSync9(packagePath)) {
44539
44723
  const pkg = readJsonObject(packagePath);
44540
44724
  if (typeof pkg.name === "string" && pkg.name !== next.name) {
44541
44725
  writeFileSync5(packagePath, `${JSON.stringify({ ...pkg, name: next.name }, null, 2)}
@@ -44566,7 +44750,7 @@ function renameInstructionFrontmatter(content, name) {
44566
44750
  return renamed + content.slice(frontmatter[0].length);
44567
44751
  }
44568
44752
  function copySkillDirectory(source, destination) {
44569
- const resolvedSource = lstatSync20(source).isSymbolicLink() ? realpathSync8(source) : source;
44753
+ const resolvedSource = lstatSync21(source).isSymbolicLink() ? realpathSync9(source) : source;
44570
44754
  mkdirSync6(destination, { recursive: true });
44571
44755
  cpSync(resolvedSource, destination, {
44572
44756
  recursive: true,
@@ -44579,7 +44763,7 @@ function copySkillDirectory(source, destination) {
44579
44763
  if (isExcludedCopyEntry(segments[i], i === 0))
44580
44764
  return false;
44581
44765
  }
44582
- if (lstatSync20(src).isSymbolicLink())
44766
+ if (lstatSync21(src).isSymbolicLink())
44583
44767
  return false;
44584
44768
  return true;
44585
44769
  }
@@ -44858,12 +45042,12 @@ function escapeJsString(value) {
44858
45042
  }
44859
45043
 
44860
45044
  // src/lib/authoring-path.ts
44861
- import { lstatSync as lstatSync21, realpathSync as realpathSync9 } from "fs";
45045
+ import { lstatSync as lstatSync22, realpathSync as realpathSync10 } from "fs";
44862
45046
  import { homedir as homedir4 } from "os";
44863
- import { basename as basename9, dirname as dirname17, join as join25, resolve as resolve16, sep as sep7 } from "path";
45047
+ import { basename as basename9, dirname as dirname17, join as join26, resolve as resolve17, sep as sep7 } from "path";
44864
45048
  var NATIVE_DISCOVERY_ROOTS = NATIVE_SKILL_ROOTS.map(([, path]) => path.split("/"));
44865
45049
  function pathParts(path) {
44866
- return resolve16(path).split(sep7).filter(Boolean);
45050
+ return resolve17(path).split(sep7).filter(Boolean);
44867
45051
  }
44868
45052
  function nativeRootMatch(path) {
44869
45053
  const parts = pathParts(path);
@@ -44877,24 +45061,24 @@ function nativeRootMatch(path) {
44877
45061
  return;
44878
45062
  }
44879
45063
  function physicalPath(path) {
44880
- let cursor = resolve16(path);
45064
+ let cursor = resolve17(path);
44881
45065
  const suffix = [];
44882
- while (!lstatSync21(cursor, { throwIfNoEntry: false })) {
45066
+ while (!lstatSync22(cursor, { throwIfNoEntry: false })) {
44883
45067
  suffix.unshift(basename9(cursor));
44884
45068
  const parent = dirname17(cursor);
44885
45069
  if (parent === cursor)
44886
- return resolve16(path);
45070
+ return resolve17(path);
44887
45071
  cursor = parent;
44888
45072
  }
44889
- return resolve16(realpathSync9(cursor), ...suffix);
45073
+ return resolve17(realpathSync10(cursor), ...suffix);
44890
45074
  }
44891
45075
  function contains(root2, path) {
44892
45076
  return path === root2 || path.startsWith(root2 + sep7);
44893
45077
  }
44894
45078
  function configuredRoots(home, explicitHome) {
44895
- const homeData = join25(home, ".hasna", "skills");
45079
+ const homeData = join26(home, ".hasna", "skills");
44896
45080
  const homePolicy = readManagedSkillPolicySnapshot(homeData);
44897
- const configuredPolicy = !explicitHome && resolve16(getDataDirReadOnly()) !== resolve16(homeData) ? readManagedSkillPolicySnapshot(getDataDirReadOnly()) : null;
45081
+ const configuredPolicy = !explicitHome && resolve17(getDataDirReadOnly()) !== resolve17(homeData) ? readManagedSkillPolicySnapshot(getDataDirReadOnly()) : null;
44898
45082
  const policy = homePolicy ?? configuredPolicy;
44899
45083
  const bridge = policy?.value.bridge;
44900
45084
  if (bridge && (typeof bridge.home !== "string" || physicalPath(bridge.home) !== physicalPath(home))) {
@@ -44923,8 +45107,8 @@ function configuredRoots(home, explicitHome) {
44923
45107
  admitBinding(binding);
44924
45108
  continue;
44925
45109
  }
44926
- const nativeHome = join25(home, agent === "opencode" ? ".config/opencode" : `.${agent}`);
44927
- if (!lstatSync21(nativeHome, { throwIfNoEntry: false }))
45110
+ const nativeHome = join26(home, agent === "opencode" ? ".config/opencode" : `.${agent}`);
45111
+ if (!lstatSync22(nativeHome, { throwIfNoEntry: false }))
44928
45112
  continue;
44929
45113
  roots.push(...resolveAgentDiscovery({ home, agent, canonical: physicalPath }).roots);
44930
45114
  }
@@ -44933,22 +45117,22 @@ function configuredRoots(home, explicitHome) {
44933
45117
  function assertPortableAuthoringPath(path, options = {}) {
44934
45118
  if (typeof path !== "string" || !path || path.includes("\x00"))
44935
45119
  throw new Error("Invalid portable authoring path");
44936
- const lexical = resolve16(path);
45120
+ const lexical = resolve17(path);
44937
45121
  const physical = physicalPath(lexical);
44938
45122
  const candidates = [lexical, physical];
44939
45123
  let native = candidates.map(nativeRootMatch).find(Boolean);
44940
- const home = resolve16(options.homeDir ?? homedir4());
44941
- const defaults = NATIVE_DISCOVERY_ROOTS.map((parts) => join25(home, ...parts));
44942
- defaults.push(join25(home, ".codex/plugins/cache"), join25(home, ".claude/plugins/cache"), join25(home, ".claude/plugins/synced"), join25(home, ".gemini/extensions"));
45124
+ const home = resolve17(options.homeDir ?? homedir4());
45125
+ const defaults = NATIVE_DISCOVERY_ROOTS.map((parts) => join26(home, ...parts));
45126
+ defaults.push(join26(home, ".codex/plugins/cache"), join26(home, ".claude/plugins/cache"), join26(home, ".claude/plugins/synced"), join26(home, ".gemini/extensions"));
44943
45127
  for (const root2 of defaults) {
44944
- if (candidates.some((candidate2) => contains(resolve16(root2), candidate2) || contains(physicalPath(root2), candidate2)))
45128
+ if (candidates.some((candidate2) => contains(resolve17(root2), candidate2) || contains(physicalPath(root2), candidate2)))
44945
45129
  native ??= root2;
44946
45130
  }
44947
45131
  if (native) {
44948
45132
  throw new Error(`Refusing portable Skills authoring below native discovery root '${native}': ${lexical}. Set HASNA_SKILLS_DIR to a private authoring corpus outside native roots.`);
44949
45133
  }
44950
45134
  for (const root2 of configuredRoots(home, options.homeDir !== undefined)) {
44951
- if (candidates.some((candidate2) => contains(resolve16(root2), candidate2) || contains(physicalPath(root2), candidate2))) {
45135
+ if (candidates.some((candidate2) => contains(resolve17(root2), candidate2) || contains(physicalPath(root2), candidate2))) {
44952
45136
  throw new Error(`Refusing portable Skills authoring below configured native discovery root: ${lexical}`);
44953
45137
  }
44954
45138
  }
@@ -44960,15 +45144,15 @@ function getPortableSkillsRoot(options = {}) {
44960
45144
  function resolvePortableSkillsRoot(options, migrate) {
44961
45145
  if (options.rootDir)
44962
45146
  return options.rootDir;
44963
- const appDir = options.homeDir ? join26(options.homeDir, ".hasna", "skills") : migrate ? getDataDir() : getDataDirReadOnly();
44964
- const cache = join26(appDir, SKILLS_CACHE_DIRNAME);
45147
+ const appDir = options.homeDir ? join27(options.homeDir, ".hasna", "skills") : migrate ? getDataDir() : getDataDirReadOnly();
45148
+ const cache = join27(appDir, SKILLS_CACHE_DIRNAME);
44965
45149
  if (isOwnerLayoutMigrated(appDir) && safeIsDirectory(cache))
44966
45150
  return cache;
44967
- const installed = join26(appDir, INSTALLED_SKILLS_DIRNAME);
45151
+ const installed = join27(appDir, INSTALLED_SKILLS_DIRNAME);
44968
45152
  return installed;
44969
45153
  }
44970
45154
  function getPortableSkillPath(name, options = {}) {
44971
- return join26(getPortableSkillsRoot(options), normalizePortableSkillName(name));
45155
+ return join27(getPortableSkillsRoot(options), normalizePortableSkillName(name));
44972
45156
  }
44973
45157
  function findPortableSkill(name, options = {}) {
44974
45158
  let normalized;
@@ -44978,7 +45162,7 @@ function findPortableSkill(name, options = {}) {
44978
45162
  return null;
44979
45163
  }
44980
45164
  const path = getPortableSkillPath(normalized, options);
44981
- if (!existsSync9(path) || !statSync9(path).isDirectory())
45165
+ if (!existsSync10(path) || !statSync9(path).isDirectory())
44982
45166
  return null;
44983
45167
  try {
44984
45168
  return summarizePortableSkill(path, normalized);
@@ -44994,7 +45178,7 @@ function listPortableSkills(options = {}) {
44994
45178
  for (const entry of readdirSync10(root2).sort()) {
44995
45179
  if (entry.startsWith("."))
44996
45180
  continue;
44997
- const path = join26(root2, entry);
45181
+ const path = join27(root2, entry);
44998
45182
  if (!safeIsDirectory(path))
44999
45183
  continue;
45000
45184
  try {
@@ -45028,11 +45212,11 @@ function isOfficialSkillName(name) {
45028
45212
  function scaffoldPortableSkill(name, options = {}) {
45029
45213
  const skillName = normalizeNewPortableSkillName(name);
45030
45214
  const readOnlyRoot = resolvePortableSkillsRoot(options, false);
45031
- assertPortableAuthoringPath(join26(readOnlyRoot, skillName), options);
45215
+ assertPortableAuthoringPath(join27(readOnlyRoot, skillName), options);
45032
45216
  const root2 = getPortableSkillsRoot(options);
45033
- const skillPath = join26(root2, skillName);
45217
+ const skillPath = join27(root2, skillName);
45034
45218
  assertPortableAuthoringPath(skillPath, options);
45035
- if (existsSync9(skillPath)) {
45219
+ if (existsSync10(skillPath)) {
45036
45220
  if (!options.overwrite)
45037
45221
  throw new Error(`Skill '${skillName}' already exists at ${skillPath}`);
45038
45222
  rmSync2(skillPath, { recursive: true, force: true });
@@ -45050,7 +45234,7 @@ function scaffoldPortableSkill(name, options = {}) {
45050
45234
  }
45051
45235
  function portPortableSkillDirectory(sourceDir, options = {}) {
45052
45236
  const absoluteSource = normalize4(sourceDir);
45053
- if (!existsSync9(absoluteSource) || !statSync9(absoluteSource).isDirectory()) {
45237
+ if (!existsSync10(absoluteSource) || !statSync9(absoluteSource).isDirectory()) {
45054
45238
  throw new Error(`Import directory not found: ${sourceDir}`);
45055
45239
  }
45056
45240
  const continueOnError = options.continueOnError ?? true;
@@ -45064,7 +45248,7 @@ function portPortableSkillDirectory(sourceDir, options = {}) {
45064
45248
  const skipped = [];
45065
45249
  const entries = readdirSync10(absoluteSource, { withFileTypes: true }).map((entry) => entry.name).filter((entryName) => !entryName.startsWith(".")).sort();
45066
45250
  for (const entryName of entries) {
45067
- const childPath = join26(absoluteSource, entryName);
45251
+ const childPath = join27(absoluteSource, entryName);
45068
45252
  if (!safeIsDirectory(childPath))
45069
45253
  continue;
45070
45254
  if (!isSkillCandidate(childPath)) {
@@ -45093,19 +45277,19 @@ function portPortableSkillDirectory(sourceDir, options = {}) {
45093
45277
  };
45094
45278
  }
45095
45279
  function isSkillCandidate(dir) {
45096
- return existsSync9(join26(dir, "SKILL.md")) || existsSync9(join26(dir, "skill.json")) || existsSync9(join26(dir, "package.json"));
45280
+ return existsSync10(join27(dir, "SKILL.md")) || existsSync10(join27(dir, "skill.json")) || existsSync10(join27(dir, "package.json"));
45097
45281
  }
45098
45282
  function physicalImportPath(path) {
45099
- let ancestor = resolve17(path);
45283
+ let ancestor = resolve18(path);
45100
45284
  const suffix = [];
45101
- while (!existsSync9(ancestor)) {
45285
+ while (!existsSync10(ancestor)) {
45102
45286
  suffix.unshift(basename10(ancestor));
45103
45287
  ancestor = dirname18(ancestor);
45104
45288
  }
45105
- return join26(realpathSync10(ancestor), ...suffix);
45289
+ return join27(realpathSync11(ancestor), ...suffix);
45106
45290
  }
45107
45291
  function assertDisjointImportPaths(source, destination) {
45108
- const sourcePath = realpathSync10(source);
45292
+ const sourcePath = realpathSync11(source);
45109
45293
  const destinationPath = physicalImportPath(destination);
45110
45294
  const contains2 = (parent, child) => {
45111
45295
  const path = relative6(parent, child);
@@ -45117,7 +45301,7 @@ function assertDisjointImportPaths(source, destination) {
45117
45301
  }
45118
45302
  function portPortableSkill(sourcePath, options = {}) {
45119
45303
  const absoluteSource = normalize4(sourcePath);
45120
- if (!existsSync9(absoluteSource) || !statSync9(absoluteSource).isDirectory()) {
45304
+ if (!existsSync10(absoluteSource) || !statSync9(absoluteSource).isDirectory()) {
45121
45305
  throw new Error(`Skill source directory not found: ${sourcePath}`);
45122
45306
  }
45123
45307
  const inferred = readPortableSkillManifestForImport(absoluteSource);
@@ -45128,14 +45312,14 @@ function portPortableSkill(sourcePath, options = {}) {
45128
45312
  const via = explicitName ? `Name '${skillName}' matches a bundled official skill.` : `Inferred name '${skillName}'${sourceSlug && sourceSlug !== skillName ? ` (from source folder '${basename10(absoluteSource)}')` : ""} matches a bundled official skill.`;
45129
45313
  throw new Error(`${via} Importing it would shadow the official '${skillName}'. ` + `Pass --name to choose a different name, or --allow-shadow to override deliberately.`);
45130
45314
  }
45131
- const readOnlyDestination = join26(resolvePortableSkillsRoot(options, false), skillName);
45315
+ const readOnlyDestination = join27(resolvePortableSkillsRoot(options, false), skillName);
45132
45316
  assertPortableAuthoringPath(readOnlyDestination, options);
45133
45317
  assertDisjointImportPaths(absoluteSource, readOnlyDestination);
45134
45318
  const root2 = getPortableSkillsRoot(options);
45135
- const destination = join26(root2, skillName);
45319
+ const destination = join27(root2, skillName);
45136
45320
  assertPortableAuthoringPath(destination, options);
45137
45321
  assertDisjointImportPaths(absoluteSource, destination);
45138
- if (existsSync9(destination)) {
45322
+ if (existsSync10(destination)) {
45139
45323
  if (!options.overwrite)
45140
45324
  throw new Error(`Skill '${skillName}' already exists at ${destination}`);
45141
45325
  rmSync2(destination, { recursive: true, force: true });
@@ -45177,13 +45361,13 @@ function buildCorpusManifest(input, name) {
45177
45361
  function writeCorpusSkill(input, options = {}) {
45178
45362
  const name = normalizePortableSkillName(input.name);
45179
45363
  const readOnlyRoot = resolvePortableSkillsRoot(options, false);
45180
- assertPortableAuthoringPath(join26(readOnlyRoot, name), options);
45364
+ assertPortableAuthoringPath(join27(readOnlyRoot, name), options);
45181
45365
  const root2 = getPortableSkillsRoot(options);
45182
- const skillPath = join26(root2, name);
45366
+ const skillPath = join27(root2, name);
45183
45367
  assertPortableAuthoringPath(skillPath, options);
45184
- const created = !existsSync9(skillPath);
45368
+ const created = !existsSync10(skillPath);
45185
45369
  mkdirSync7(skillPath, { recursive: true });
45186
- writeFileSync6(join26(skillPath, "SKILL.md"), input.skillMd);
45370
+ writeFileSync6(join27(skillPath, "SKILL.md"), input.skillMd);
45187
45371
  const manifest = buildCorpusManifest(input, name);
45188
45372
  writeSkillJsonWithHash(skillPath, manifest);
45189
45373
  return { name, path: skillPath, manifest, created };
@@ -45191,22 +45375,22 @@ function writeCorpusSkill(input, options = {}) {
45191
45375
  function installCorpusSkillAtomically(input, options = {}) {
45192
45376
  const name = normalizePortableSkillName(input.name);
45193
45377
  const readOnlyRoot = resolvePortableSkillsRoot(options, false);
45194
- assertPortableAuthoringPath(join26(readOnlyRoot, name), options);
45378
+ assertPortableAuthoringPath(join27(readOnlyRoot, name), options);
45195
45379
  const root2 = getPortableSkillsRoot(options);
45196
- const target = join26(root2, name);
45380
+ const target = join27(root2, name);
45197
45381
  assertPortableAuthoringPath(target, options);
45198
- const created = !existsSync9(target);
45382
+ const created = !existsSync10(target);
45199
45383
  mkdirSync7(root2, { recursive: true });
45200
- const staging = mkdtempSync(join26(root2, `.pull-${name}-`));
45384
+ const staging = mkdtempSync(join27(root2, `.pull-${name}-`));
45201
45385
  let moved = false;
45202
45386
  let backup = null;
45203
45387
  try {
45204
- writeFileSync6(join26(staging, "SKILL.md"), input.skillMd);
45388
+ writeFileSync6(join27(staging, "SKILL.md"), input.skillMd);
45205
45389
  const manifest = buildCorpusManifest(input, name);
45206
45390
  writeSkillJsonWithHash(staging, manifest);
45207
- if (existsSync9(target)) {
45208
- backup = mkdtempSync(join26(root2, `.pull-backup-${name}-`));
45209
- renameSync4(target, join26(backup, name));
45391
+ if (existsSync10(target)) {
45392
+ backup = mkdtempSync(join27(root2, `.pull-backup-${name}-`));
45393
+ renameSync4(target, join27(backup, name));
45210
45394
  moved = true;
45211
45395
  }
45212
45396
  renameSync4(staging, target);
@@ -45215,9 +45399,9 @@ function installCorpusSkillAtomically(input, options = {}) {
45215
45399
  return { name, path: target, manifest, created };
45216
45400
  } catch (error) {
45217
45401
  rmSync2(staging, { recursive: true, force: true });
45218
- if (moved && backup && existsSync9(join26(backup, name))) {
45402
+ if (moved && backup && existsSync10(join27(backup, name))) {
45219
45403
  try {
45220
- renameSync4(join26(backup, name), target);
45404
+ renameSync4(join27(backup, name), target);
45221
45405
  } catch {}
45222
45406
  }
45223
45407
  throw error;
@@ -45229,10 +45413,10 @@ function validatePortableSkillDirectory(name, skillPath) {
45229
45413
  const issues = [...base.issues];
45230
45414
  const warnings = [...base.warnings];
45231
45415
  let manifest;
45232
- if (existsSync9(skillPath)) {
45233
- const skillJsonPath = join26(skillPath, "skill.json");
45234
- const skillMdPath = join26(skillPath, "SKILL.md");
45235
- if (!existsSync9(skillJsonPath) && !existsSync9(skillMdPath)) {
45416
+ if (existsSync10(skillPath)) {
45417
+ const skillJsonPath = join27(skillPath, "skill.json");
45418
+ const skillMdPath = join27(skillPath, "SKILL.md");
45419
+ if (!existsSync10(skillJsonPath) && !existsSync10(skillMdPath)) {
45236
45420
  add3(issues, "portable.manifest_missing", "Missing portable manifest: expected SKILL.md frontmatter and/or skill.json");
45237
45421
  }
45238
45422
  try {
@@ -45251,7 +45435,7 @@ function validatePortableSkillDirectory(name, skillPath) {
45251
45435
  add3(issues, "portable.version_missing", "Portable manifest missing version");
45252
45436
  }
45253
45437
  const contractIssues = validatePortableManifestContract(manifest, {
45254
- strict: existsSync9(join26(skillPath, "skill.json")),
45438
+ strict: existsSync10(join27(skillPath, "skill.json")),
45255
45439
  skillPath
45256
45440
  });
45257
45441
  for (const issue of contractIssues)
@@ -45291,8 +45475,8 @@ function validatePortableSkillDirectory(name, skillPath) {
45291
45475
  add3(issues, "portable.command_entry_unsafe", `Command '${command.name}' entry '${command.entry}' must stay inside the skill directory`);
45292
45476
  continue;
45293
45477
  }
45294
- const entryPath = join26(skillPath, command.entry);
45295
- if (!existsSync9(entryPath))
45478
+ const entryPath = join27(skillPath, command.entry);
45479
+ if (!existsSync10(entryPath))
45296
45480
  add3(issues, "portable.command_entry_missing", `Command '${command.name}' entry '${command.entry}' is missing`);
45297
45481
  else if (statSync9(entryPath).isDirectory())
45298
45482
  add3(issues, "portable.command_entry_directory", `Command '${command.name}' entry '${command.entry}' must be a file`);
@@ -45302,7 +45486,7 @@ function validatePortableSkillDirectory(name, skillPath) {
45302
45486
  } catch (error) {
45303
45487
  add3(issues, "portable.manifest_invalid", error.message);
45304
45488
  }
45305
- if (manifest?.kind !== "instruction" && !existsSync9(join26(skillPath, "AGENTS.md"))) {
45489
+ if (manifest?.kind !== "instruction" && !existsSync10(join27(skillPath, "AGENTS.md"))) {
45306
45490
  add3(issues, "portable.agents_missing", "Missing AGENTS.md with build-out instructions for coding agents");
45307
45491
  }
45308
45492
  }
@@ -45338,13 +45522,13 @@ async function runPortableSkill(name, args, options = {}) {
45338
45522
  if (!isSafeRelativePath2(command.entry)) {
45339
45523
  return { exitCode: 1, error: `Portable skill '${name}' command entry is unsafe` };
45340
45524
  }
45341
- const entryPath = join26(skill.path, command.entry);
45342
- if (!existsSync9(entryPath)) {
45525
+ const entryPath = join27(skill.path, command.entry);
45526
+ if (!existsSync10(entryPath)) {
45343
45527
  return { exitCode: 1, error: `Entry point '${command.entry}' not found in portable skill '${name}'` };
45344
45528
  }
45345
- const pkgPath = join26(skill.path, "package.json");
45346
- const nodeModules = join26(skill.path, "node_modules");
45347
- if (existsSync9(pkgPath) && !existsSync9(nodeModules) && hasPackageDependencies(pkgPath)) {
45529
+ const pkgPath = join27(skill.path, "package.json");
45530
+ const nodeModules = join27(skill.path, "node_modules");
45531
+ if (existsSync10(pkgPath) && !existsSync10(nodeModules) && hasPackageDependencies(pkgPath)) {
45348
45532
  const install = Bun.spawn(["bun", "install", "--no-save"], {
45349
45533
  cwd: skill.path,
45350
45534
  stdout: "pipe",
@@ -45415,9 +45599,9 @@ function isSkillsOwnershipMarker(marker) {
45415
45599
  return typeof marker === "object" && marker !== null && Object.hasOwn(marker, "managedBy") && marker.managedBy === SYNC_MARKER_MANAGED_BY;
45416
45600
  }
45417
45601
  function hasSkillsOwnershipMarker(dir) {
45418
- const path = join27(dir, SYNC_MARKER_FILE);
45602
+ const path = join28(dir, SYNC_MARKER_FILE);
45419
45603
  try {
45420
- if (!lstatSync22(path).isFile())
45604
+ if (!lstatSync23(path).isFile())
45421
45605
  return false;
45422
45606
  const marker = JSON.parse(readFileSync17(path, "utf8"));
45423
45607
  return isSkillsOwnershipMarker(marker);
@@ -45439,9 +45623,9 @@ function resolveSyncAgents(arg) {
45439
45623
  function agentGlobalSkillsDir(agent, homeDir3 = homedir5()) {
45440
45624
  switch (agent) {
45441
45625
  case "opencode":
45442
- return join27(homeDir3, ".config", "opencode", "skills");
45626
+ return join28(homeDir3, ".config", "opencode", "skills");
45443
45627
  default:
45444
- return join27(homeDir3, `.${agent}`, "skills");
45628
+ return join28(homeDir3, `.${agent}`, "skills");
45445
45629
  }
45446
45630
  }
45447
45631
  function adaptSkillMdForAgent(skillMd, agent) {
@@ -45500,8 +45684,8 @@ function resolveSyncCorpus(options = {}) {
45500
45684
  function packageSourceRoots(source) {
45501
45685
  const roots = [];
45502
45686
  for (const sub of ["skills"]) {
45503
- const candidate2 = join27(source, sub);
45504
- if (existsSync10(candidate2) && isDirectory(candidate2))
45687
+ const candidate2 = join28(source, sub);
45688
+ if (existsSync11(candidate2) && isDirectory(candidate2))
45505
45689
  roots.push(candidate2);
45506
45690
  }
45507
45691
  if (roots.length > 0)
@@ -45516,10 +45700,10 @@ function containsSkillDirectories(path) {
45516
45700
  return false;
45517
45701
  }
45518
45702
  return entries.some((entry) => {
45519
- const candidate2 = join27(path, entry);
45703
+ const candidate2 = join28(path, entry);
45520
45704
  if (!isDirectory(candidate2))
45521
45705
  return false;
45522
- return existsSync10(join27(candidate2, "SKILL.md")) || existsSync10(join27(candidate2, "skill.json")) || existsSync10(join27(candidate2, "package.json"));
45706
+ return existsSync11(join28(candidate2, "SKILL.md")) || existsSync11(join28(candidate2, "skill.json")) || existsSync11(join28(candidate2, "package.json"));
45523
45707
  });
45524
45708
  }
45525
45709
  function isDirectory(path) {
@@ -45559,7 +45743,7 @@ function syncSkillsToAgents(options = {}) {
45559
45743
  actions.push({
45560
45744
  skill: name,
45561
45745
  agent,
45562
- path: join27(agentGlobalSkillsDir(agent, homeDir3), name, "SKILL.md"),
45746
+ path: join28(agentGlobalSkillsDir(agent, homeDir3), name, "SKILL.md"),
45563
45747
  action: "skip",
45564
45748
  reason: "not found in this machine's corpus"
45565
45749
  });
@@ -45589,7 +45773,7 @@ function syncSkillsToAgents(options = {}) {
45589
45773
  }
45590
45774
  function writeManagedAgentSkill(params) {
45591
45775
  const homeDir3 = params.homeDir ?? homedir5();
45592
- const dir = join27(agentGlobalSkillsDir(params.agent, homeDir3), params.skill);
45776
+ const dir = join28(agentGlobalSkillsDir(params.agent, homeDir3), params.skill);
45593
45777
  const result = writeManagedSkillDir(dir, params.skillMd, {
45594
45778
  skill: params.skill,
45595
45779
  source: params.source,
@@ -45606,11 +45790,11 @@ function writeManagedAgentSkill(params) {
45606
45790
  };
45607
45791
  }
45608
45792
  function writeManagedSkillDir(dir, skillMd, options) {
45609
- const skillMdPath = join27(dir, "SKILL.md");
45610
- const markerPath = join27(dir, SYNC_MARKER_FILE);
45611
- const dirExists = existsSync10(dir);
45793
+ const skillMdPath = join28(dir, "SKILL.md");
45794
+ const markerPath = join28(dir, SYNC_MARKER_FILE);
45795
+ const dirExists = existsSync11(dir);
45612
45796
  const managed = hasSkillsOwnershipMarker(dir);
45613
- const hasSkillMd = existsSync10(skillMdPath);
45797
+ const hasSkillMd = existsSync11(skillMdPath);
45614
45798
  if (dirExists && !managed && !hasSkillMd) {
45615
45799
  return {
45616
45800
  action: "skip",
@@ -45622,7 +45806,7 @@ function writeManagedSkillDir(dir, skillMd, options) {
45622
45806
  return {
45623
45807
  action: "skip",
45624
45808
  path: skillMdPath,
45625
- reason: existsSync10(markerPath) ? "an unmanaged SKILL.md already exists here (invalid or foreign ownership marker); pass --force to overwrite" : "an unmanaged SKILL.md already exists here (hand-authored); pass --force to overwrite"
45809
+ reason: existsSync11(markerPath) ? "an unmanaged SKILL.md already exists here (invalid or foreign ownership marker); pass --force to overwrite" : "an unmanaged SKILL.md already exists here (hand-authored); pass --force to overwrite"
45626
45810
  };
45627
45811
  }
45628
45812
  if (dirExists && managed && hasSkillMd && !options.force && isPointerSkillMd(skillMd)) {
@@ -45645,11 +45829,11 @@ function writeManagedSkillDir(dir, skillMd, options) {
45645
45829
  return { action, path: skillMdPath };
45646
45830
  const parentDir = dirname19(dir);
45647
45831
  mkdirSync8(parentDir, { recursive: true });
45648
- const transactionDir = mkdtempSync2(join27(parentDir, `.hasna-skills-write-${basename11(dir)}-`));
45649
- const candidateDir = join27(transactionDir, "candidate");
45650
- const backupDir = join27(transactionDir, "backup");
45651
- const candidateSkillMdPath = join27(candidateDir, "SKILL.md");
45652
- const candidateMarkerPath = join27(candidateDir, SYNC_MARKER_FILE);
45832
+ const transactionDir = mkdtempSync2(join28(parentDir, `.hasna-skills-write-${basename11(dir)}-`));
45833
+ const candidateDir = join28(transactionDir, "candidate");
45834
+ const backupDir = join28(transactionDir, "backup");
45835
+ const candidateSkillMdPath = join28(candidateDir, "SKILL.md");
45836
+ const candidateMarkerPath = join28(candidateDir, SYNC_MARKER_FILE);
45653
45837
  const marker = {
45654
45838
  managedBy: SYNC_MARKER_MANAGED_BY,
45655
45839
  skill: options.skill,
@@ -45676,9 +45860,9 @@ function writeManagedSkillDir(dir, skillMd, options) {
45676
45860
  }
45677
45861
  renameDirectory(candidateDir, dir);
45678
45862
  } catch (error) {
45679
- if (originalMoved && existsSync10(backupDir)) {
45863
+ if (originalMoved && existsSync11(backupDir)) {
45680
45864
  try {
45681
- if (existsSync10(dir))
45865
+ if (existsSync11(dir))
45682
45866
  rmSync3(dir, { recursive: true, force: true });
45683
45867
  renameDirectory(backupDir, dir);
45684
45868
  originalMoved = false;
@@ -45698,7 +45882,7 @@ function writeManagedSkillDir(dir, skillMd, options) {
45698
45882
  return { action, path: skillMdPath };
45699
45883
  }
45700
45884
  function removeManagedAgentSkill(skill, agent, homeDir3 = homedir5()) {
45701
- const dir = join27(agentGlobalSkillsDir(agent, homeDir3), skill);
45885
+ const dir = join28(agentGlobalSkillsDir(agent, homeDir3), skill);
45702
45886
  if (!hasSkillsOwnershipMarker(dir))
45703
45887
  return false;
45704
45888
  rmSync3(dir, { recursive: true, force: true });
@@ -45706,8 +45890,8 @@ function removeManagedAgentSkill(skill, agent, homeDir3 = homedir5()) {
45706
45890
  }
45707
45891
  function sourceSkillMd(skillPath, name, description, kind, preferBundledDocs = false) {
45708
45892
  if (kind === undefined || kind === "instruction" || preferBundledDocs) {
45709
- const skillMdPath = join27(skillPath, "SKILL.md");
45710
- if (existsSync10(skillMdPath))
45893
+ const skillMdPath = join28(skillPath, "SKILL.md");
45894
+ if (existsSync11(skillMdPath))
45711
45895
  return readFileSync17(skillMdPath, "utf-8");
45712
45896
  }
45713
45897
  return pointerSkillMd(name, description);
@@ -45738,8 +45922,8 @@ function normalizeSkillName(name) {
45738
45922
  }
45739
45923
 
45740
45924
  // src/lib/registry.ts
45741
- import { existsSync as existsSync11, readFileSync as readFileSync18, readdirSync as readdirSync12 } from "fs";
45742
- import { join as join28 } from "path";
45925
+ import { existsSync as existsSync12, readFileSync as readFileSync18, readdirSync as readdirSync12 } from "fs";
45926
+ import { join as join29 } from "path";
45743
45927
 
45744
45928
  // src/lib/registry-merge.ts
45745
45929
  var SKILL_SOURCE_PRECEDENCE = {
@@ -45941,7 +46125,7 @@ function parseSkillMdFrontmatter(content) {
45941
46125
  return Object.keys(result).length > 0 ? result : null;
45942
46126
  }
45943
46127
  function discoverSkillsInDir(dir, source = "custom") {
45944
- if (!existsSync11(dir))
46128
+ if (!existsSync12(dir))
45945
46129
  return [];
45946
46130
  const result = [];
45947
46131
  try {
@@ -45949,8 +46133,8 @@ function discoverSkillsInDir(dir, source = "custom") {
45949
46133
  for (const entry of entries) {
45950
46134
  if (!entry.isDirectory())
45951
46135
  continue;
45952
- const skillMdPath = join28(dir, entry.name, "SKILL.md");
45953
- if (!existsSync11(skillMdPath))
46136
+ const skillMdPath = join29(dir, entry.name, "SKILL.md");
46137
+ if (!existsSync12(skillMdPath))
45954
46138
  continue;
45955
46139
  let content;
45956
46140
  try {
@@ -45969,7 +46153,7 @@ function discoverSkillsInDir(dir, source = "custom") {
45969
46153
  category: fm.category || "Development Tools",
45970
46154
  tags: fm.tags || [],
45971
46155
  ...fm.kind ? { kind: fm.kind } : {},
45972
- ...isHostedMetadataSkillDir(join28(dir, entry.name)) ? { serverOwned: true } : {},
46156
+ ...isHostedMetadataSkillDir(join29(dir, entry.name)) ? { serverOwned: true } : {},
45973
46157
  source
45974
46158
  });
45975
46159
  }
@@ -45978,16 +46162,16 @@ function discoverSkillsInDir(dir, source = "custom") {
45978
46162
  }
45979
46163
  function findExtensionSkillPath(name) {
45980
46164
  const config = loadConfig();
45981
- if (!config.extensionsDir || !existsSync11(config.extensionsDir))
46165
+ if (!config.extensionsDir || !existsSync12(config.extensionsDir))
45982
46166
  return null;
45983
46167
  try {
45984
46168
  const entries = readdirSync12(config.extensionsDir, { withFileTypes: true });
45985
46169
  for (const entry of entries) {
45986
46170
  if (!entry.isDirectory())
45987
46171
  continue;
45988
- const skillDir = join28(config.extensionsDir, entry.name);
45989
- const skillMdPath = join28(skillDir, "SKILL.md");
45990
- if (!existsSync11(skillMdPath))
46172
+ const skillDir = join29(config.extensionsDir, entry.name);
46173
+ const skillMdPath = join29(skillDir, "SKILL.md");
46174
+ if (!existsSync12(skillMdPath))
45991
46175
  continue;
45992
46176
  let content;
45993
46177
  try {
@@ -46034,21 +46218,21 @@ function clearRegistryCache() {
46034
46218
  registryCacheTime = 0;
46035
46219
  registryCacheKey = null;
46036
46220
  }
46037
- function getSkillsByCategory(category) {
46038
- return loadRegistry().filter((s) => s.category === category);
46221
+ function getSkillsByCategory(category, catalog) {
46222
+ return (catalog ?? loadRegistry()).filter((s) => s.category === category);
46039
46223
  }
46040
46224
  function getSkill(name) {
46041
46225
  const registry = loadRegistry();
46042
46226
  const slug = normalizeSkillSlug(name);
46043
46227
  return registry.find((s) => s.name === slug) ?? registry.find((s) => s.name === resolveSkillAlias(slug));
46044
46228
  }
46045
- function getSkillsByTag(tag) {
46229
+ function getSkillsByTag(tag, catalog) {
46046
46230
  const needle = tag.toLowerCase();
46047
- return loadRegistry().filter((s) => s.tags.some((t2) => t2.toLowerCase().includes(needle)));
46231
+ return (catalog ?? loadRegistry()).filter((s) => s.tags.some((t2) => t2.toLowerCase().includes(needle)));
46048
46232
  }
46049
- function getAllTags() {
46233
+ function getAllTags(catalog) {
46050
46234
  const tagSet = new Set;
46051
- for (const skill of loadRegistry()) {
46235
+ for (const skill of catalog ?? loadRegistry()) {
46052
46236
  for (const tag of skill.tags)
46053
46237
  tagSet.add(tag.toLowerCase());
46054
46238
  }
@@ -46056,8 +46240,8 @@ function getAllTags() {
46056
46240
  }
46057
46241
 
46058
46242
  // src/lib/project-state.ts
46059
- import { existsSync as existsSync12, mkdirSync as mkdirSync9, readFileSync as readFileSync19, writeFileSync as writeFileSync8 } from "fs";
46060
- import { join as join29 } from "path";
46243
+ import { existsSync as existsSync13, mkdirSync as mkdirSync9, readFileSync as readFileSync19, writeFileSync as writeFileSync8 } from "fs";
46244
+ import { join as join30 } from "path";
46061
46245
  var VALID_PIN_SOURCES = [
46062
46246
  "official",
46063
46247
  "custom",
@@ -46072,14 +46256,14 @@ var SKILLS_PROJECT_DIR = ".skills";
46072
46256
  var PROJECT_CONFIG_FILE = "project.json";
46073
46257
  var DEFAULT_EXPORT_DIR = ".skills/exports";
46074
46258
  function getProjectStateDir(targetDir = process.cwd()) {
46075
- return join29(targetDir, SKILLS_PROJECT_DIR);
46259
+ return join30(targetDir, SKILLS_PROJECT_DIR);
46076
46260
  }
46077
46261
  function getProjectConfigPath(targetDir = process.cwd()) {
46078
- return join29(getProjectStateDir(targetDir), PROJECT_CONFIG_FILE);
46262
+ return join30(getProjectStateDir(targetDir), PROJECT_CONFIG_FILE);
46079
46263
  }
46080
46264
  function loadProjectConfig(targetDir = process.cwd()) {
46081
46265
  const path = getProjectConfigPath(targetDir);
46082
- if (!existsSync12(path))
46266
+ if (!existsSync13(path))
46083
46267
  return null;
46084
46268
  try {
46085
46269
  return normalizeProjectConfig(JSON.parse(readFileSync19(path, "utf-8")));
@@ -46204,19 +46388,19 @@ function getSkillPath(name) {
46204
46388
  const extensionPath = findExtensionSkillPath(skillName);
46205
46389
  if (extensionPath)
46206
46390
  return extensionPath;
46207
- return join30(getPortableSkillsRoot(), skillName);
46391
+ return join31(getPortableSkillsRoot(), skillName);
46208
46392
  }
46209
46393
  function getCanonicalSkillName(name) {
46210
46394
  return getSkill(name)?.name ?? resolveSkillAlias(normalizeSkillSlug(name));
46211
46395
  }
46212
46396
  function skillExists(name) {
46213
- return existsSync13(getSkillPath(name));
46397
+ return existsSync14(getSkillPath(name));
46214
46398
  }
46215
46399
  function installSkill(name, options = {}) {
46216
46400
  const { targetDir = process.cwd(), overwrite = false } = options;
46217
46401
  const canonicalName = getCanonicalSkillName(name);
46218
46402
  const skillName = normalizeSkillName(canonicalName);
46219
- if (!existsSync13(getSkillPath(name))) {
46403
+ if (!existsSync14(getSkillPath(name))) {
46220
46404
  const knownOfficial = Boolean(getSkill(name));
46221
46405
  return {
46222
46406
  skill: canonicalName,
@@ -46243,7 +46427,7 @@ function installSkill(name, options = {}) {
46243
46427
  }
46244
46428
  function installSkillSource(name, _options = {}) {
46245
46429
  const canonicalName = getCanonicalSkillName(name);
46246
- if (!existsSync13(getSkillPath(name))) {
46430
+ if (!existsSync14(getSkillPath(name))) {
46247
46431
  return { skill: canonicalName, success: false, error: `Skill '${name}' not found`, mode: "source" };
46248
46432
  }
46249
46433
  return {
@@ -46264,11 +46448,11 @@ function installSkillManifest(manifest, _options = {}) {
46264
46448
  }
46265
46449
  function createLocalSkillManifest(name, generateSkillMd) {
46266
46450
  const sourcePath = getSkillPath(name);
46267
- if (!existsSync13(sourcePath))
46451
+ if (!existsSync14(sourcePath))
46268
46452
  return null;
46269
46453
  let skillMd = "";
46270
- const skillMdPath = join30(sourcePath, "SKILL.md");
46271
- if (existsSync13(skillMdPath)) {
46454
+ const skillMdPath = join31(sourcePath, "SKILL.md");
46455
+ if (existsSync14(skillMdPath)) {
46272
46456
  skillMd = readFileSync20(skillMdPath, "utf-8");
46273
46457
  } else if (generateSkillMd) {
46274
46458
  skillMd = generateSkillMd(name) ?? "";
@@ -46341,21 +46525,21 @@ function getAgentSkillsDir(agent, scope = "global", projectDir) {
46341
46525
  const base = projectDir || process.cwd();
46342
46526
  switch (agent) {
46343
46527
  case "pi":
46344
- return scope === "project" ? join30(base, ".pi", "skills") : join30(homedir6(), ".pi", "agent", "skills");
46528
+ return scope === "project" ? join31(base, ".pi", "skills") : join31(homedir6(), ".pi", "agent", "skills");
46345
46529
  case "opencode":
46346
- return scope === "project" ? join30(base, ".opencode", "skills") : join30(homedir6(), ".config", "opencode", "skills");
46530
+ return scope === "project" ? join31(base, ".opencode", "skills") : join31(homedir6(), ".config", "opencode", "skills");
46347
46531
  default:
46348
- return scope === "project" ? join30(base, `.${agent}`, "skills") : join30(homedir6(), `.${agent}`, "skills");
46532
+ return scope === "project" ? join31(base, `.${agent}`, "skills") : join31(homedir6(), `.${agent}`, "skills");
46349
46533
  }
46350
46534
  }
46351
46535
  function getAgentSkillPath(name, agent, scope = "global", projectDir) {
46352
46536
  const skillName = normalizeSkillName(getCanonicalSkillName(name));
46353
- return join30(getAgentSkillsDir(agent, scope, projectDir), skillName);
46537
+ return join31(getAgentSkillsDir(agent, scope, projectDir), skillName);
46354
46538
  }
46355
46539
  function installSkillForAgent(name, options, generateSkillMd) {
46356
46540
  assertNativeExportAllowed();
46357
46541
  const canonicalName = getCanonicalSkillName(name);
46358
- if (!existsSync13(getSkillPath(name))) {
46542
+ if (!existsSync14(getSkillPath(name))) {
46359
46543
  return { skill: canonicalName, success: false, error: `Skill '${name}' not found` };
46360
46544
  }
46361
46545
  const scope = options.scope ?? "global";
@@ -46386,8 +46570,8 @@ function removeSkillForAgent(name, options) {
46386
46570
  }
46387
46571
  function resolveAgentSkillMd(name, generateSkillMd) {
46388
46572
  const sourcePath = getSkillPath(name);
46389
- const skillMdPath = join30(sourcePath, "SKILL.md");
46390
- if (existsSync13(skillMdPath))
46573
+ const skillMdPath = join31(sourcePath, "SKILL.md");
46574
+ if (existsSync14(skillMdPath))
46391
46575
  return readFileSync20(skillMdPath, "utf-8");
46392
46576
  if (generateSkillMd)
46393
46577
  return generateSkillMd(name);
@@ -46406,7 +46590,7 @@ function warnMissingDependencies(name, targetDir) {
46406
46590
  }
46407
46591
  function generateMinimalSkillMd(name) {
46408
46592
  const sourcePath = getSkillPath(name);
46409
- if (!existsSync13(sourcePath))
46593
+ if (!existsSync14(sourcePath))
46410
46594
  return null;
46411
46595
  const canonicalName = getCanonicalSkillName(name);
46412
46596
  const meta = getSkill(canonicalName);
@@ -46421,7 +46605,7 @@ function generateMinimalSkillMd(name) {
46421
46605
  "---",
46422
46606
  ""
46423
46607
  ].filter(Boolean);
46424
- const fallbackDoc = readFileIfExists(join30(sourcePath, "README.md")) || readFileIfExists(join30(sourcePath, "CLAUDE.md"));
46608
+ const fallbackDoc = readFileIfExists(join31(sourcePath, "README.md")) || readFileIfExists(join31(sourcePath, "CLAUDE.md"));
46425
46609
  if (fallbackDoc)
46426
46610
  return `${frontmatter.join(`
46427
46611
  `)}${fallbackDoc.trim()}
@@ -46440,8 +46624,8 @@ skills run ${canonicalName}
46440
46624
  `;
46441
46625
  }
46442
46626
  function readBundledSkillVersion(name) {
46443
- const pkgPath = join30(getSkillPath(name), "package.json");
46444
- if (!existsSync13(pkgPath))
46627
+ const pkgPath = join31(getSkillPath(name), "package.json");
46628
+ if (!existsSync14(pkgPath))
46445
46629
  return "unknown";
46446
46630
  try {
46447
46631
  const pkg = JSON.parse(readFileSync20(pkgPath, "utf-8"));
@@ -46451,7 +46635,7 @@ function readBundledSkillVersion(name) {
46451
46635
  }
46452
46636
  }
46453
46637
  function readFileIfExists(path) {
46454
- return existsSync13(path) ? readFileSync20(path, "utf-8") : null;
46638
+ return existsSync14(path) ? readFileSync20(path, "utf-8") : null;
46455
46639
  }
46456
46640
  function loadProjectConfigCompat(targetDir) {
46457
46641
  return loadProjectConfig(targetDir);
@@ -46495,8 +46679,8 @@ function selectSkillDoc(docs, file) {
46495
46679
  function isInstructionSkillDir(skillPath, meta) {
46496
46680
  if (meta?.kind === "instruction")
46497
46681
  return true;
46498
- const skillMdPath = join31(skillPath, "SKILL.md");
46499
- if (!existsSync14(skillMdPath))
46682
+ const skillMdPath = join32(skillPath, "SKILL.md");
46683
+ if (!existsSync15(skillMdPath))
46500
46684
  return false;
46501
46685
  try {
46502
46686
  return parseSkillFrontmatter(readFileSync21(skillMdPath, "utf-8"))?.kind === "instruction";
@@ -46522,12 +46706,12 @@ var HOSTED_PROVIDER_ENV_PREFIXES = [
46522
46706
  ];
46523
46707
  function getSkillDocs(name) {
46524
46708
  const skillPath = getSkillPath(name);
46525
- if (!existsSync14(skillPath))
46709
+ if (!existsSync15(skillPath))
46526
46710
  return null;
46527
46711
  return {
46528
- skillMd: readIfExists(join31(skillPath, "SKILL.md")),
46529
- readme: readIfExists(join31(skillPath, "README.md")),
46530
- claudeMd: readIfExists(join31(skillPath, "CLAUDE.md"))
46712
+ skillMd: readIfExists(join32(skillPath, "SKILL.md")),
46713
+ readme: readIfExists(join32(skillPath, "README.md")),
46714
+ claudeMd: readIfExists(join32(skillPath, "CLAUDE.md"))
46531
46715
  };
46532
46716
  }
46533
46717
  function getSkillBestDoc(name, file) {
@@ -46539,18 +46723,18 @@ function getSkillBestDoc(name, file) {
46539
46723
  }
46540
46724
  function getSkillRequirements(name) {
46541
46725
  const skillPath = getSkillPath(name);
46542
- if (!existsSync14(skillPath))
46726
+ if (!existsSync15(skillPath))
46543
46727
  return null;
46544
46728
  const texts = [];
46545
46729
  for (const file of ["SKILL.md", "README.md", "CLAUDE.md", ".env.example", ".env.local.example"]) {
46546
- const content = readIfExists(join31(skillPath, file));
46730
+ const content = readIfExists(join32(skillPath, file));
46547
46731
  if (content)
46548
46732
  texts.push(content);
46549
46733
  }
46550
46734
  const meta = getSkill(name);
46551
46735
  let dependencies = {};
46552
46736
  try {
46553
- dependencies = JSON.parse(readFileSync21(join31(skillPath, "package.json"), "utf8")).dependencies || {};
46737
+ dependencies = JSON.parse(readFileSync21(join32(skillPath, "package.json"), "utf8")).dependencies || {};
46554
46738
  } catch {}
46555
46739
  return getSkillRequirementsFromContent(name, texts, dependencies, meta);
46556
46740
  }
@@ -46603,7 +46787,7 @@ async function runSkill(name, args, options = {}) {
46603
46787
  const meta = getSkill(name);
46604
46788
  const canonicalName = meta?.name ?? name;
46605
46789
  const skillPath = getSkillPath(canonicalName);
46606
- if (!existsSync14(skillPath)) {
46790
+ if (!existsSync15(skillPath)) {
46607
46791
  return { exitCode: 1, error: `Skill '${name}' not found` };
46608
46792
  }
46609
46793
  if (isInstructionSkillDir(skillPath, meta)) {
@@ -46612,8 +46796,8 @@ async function runSkill(name, args, options = {}) {
46612
46796
  error: `Skill '${name}' is an instruction skill (kind: instruction) and is not runnable. Instruction skills are consumed by coding agents via SKILL.md, not executed with 'skills run'.`
46613
46797
  };
46614
46798
  }
46615
- const pkgPath = join31(skillPath, "package.json");
46616
- if (!existsSync14(pkgPath)) {
46799
+ const pkgPath = join32(skillPath, "package.json");
46800
+ if (!existsSync15(pkgPath)) {
46617
46801
  return { exitCode: 1, error: `No package.json in skill '${name}'` };
46618
46802
  }
46619
46803
  let entryPoint2;
@@ -46632,12 +46816,12 @@ async function runSkill(name, args, options = {}) {
46632
46816
  } catch {
46633
46817
  return { exitCode: 1, error: `Failed to parse package.json for skill '${name}'` };
46634
46818
  }
46635
- const entryPath = join31(skillPath, entryPoint2);
46636
- if (!existsSync14(entryPath)) {
46819
+ const entryPath = join32(skillPath, entryPoint2);
46820
+ if (!existsSync15(entryPath)) {
46637
46821
  return { exitCode: 1, error: `Entry point '${entryPoint2}' not found in skill '${name}'` };
46638
46822
  }
46639
46823
  const env = { ...process.env, ...options.env };
46640
- if (!existsSync14(join31(skillPath, "node_modules")) || hasDependencyPreparationMarker(skillPath)) {
46824
+ if (!existsSync15(join32(skillPath, "node_modules")) || hasDependencyPreparationMarker(skillPath)) {
46641
46825
  const failure = await prepareSkillDependencies(skillPath, env, options.preparationTimeoutMs);
46642
46826
  if (failure)
46643
46827
  return failure;
@@ -46706,7 +46890,7 @@ function generateSkillMd(name) {
46706
46890
  if (!meta)
46707
46891
  return null;
46708
46892
  const skillPath = getSkillPath(name);
46709
- if (!existsSync14(skillPath))
46893
+ if (!existsSync15(skillPath))
46710
46894
  return null;
46711
46895
  const frontmatter = [
46712
46896
  "---",
@@ -46715,11 +46899,11 @@ function generateSkillMd(name) {
46715
46899
  "---"
46716
46900
  ].join(`
46717
46901
  `);
46718
- const readme = readIfExists(join31(skillPath, "README.md"));
46719
- const claudeMd = readIfExists(join31(skillPath, "CLAUDE.md"));
46902
+ const readme = readIfExists(join32(skillPath, "README.md"));
46903
+ const claudeMd = readIfExists(join32(skillPath, "CLAUDE.md"));
46720
46904
  let cliCommand = null;
46721
- const pkgPath = join31(skillPath, "package.json");
46722
- if (existsSync14(pkgPath)) {
46905
+ const pkgPath = join32(skillPath, "package.json");
46906
+ if (existsSync15(pkgPath)) {
46723
46907
  try {
46724
46908
  const pkg = JSON.parse(readFileSync21(pkgPath, "utf-8"));
46725
46909
  if (pkg.bin) {
@@ -46796,7 +46980,7 @@ function extractEnvVars(text2) {
46796
46980
  }
46797
46981
  function readIfExists(path) {
46798
46982
  try {
46799
- if (existsSync14(path)) {
46983
+ if (existsSync15(path)) {
46800
46984
  return readFileSync21(path, "utf-8");
46801
46985
  }
46802
46986
  } catch {}
@@ -46863,6 +47047,8 @@ async function syncSelectionProfile(profileId, options = {}) {
46863
47047
  async function resolveSelectionContext(profileId, options = {}) {
46864
47048
  const sessionState = options.sessionId ? readSkillSessionSnapshotIfExists(options.sessionId, options) : null;
46865
47049
  const session = sessionState?.receipt ?? null;
47050
+ if (options.nativeParentSessionId !== undefined && session && (session.parent?.sessionId ?? null) !== options.nativeParentSessionId)
47051
+ throw new SkillSelectionError("SESSION_PARENT_MISMATCH", "The native session id is already bound to different parent custody.");
46866
47052
  const parentState = !session && options.parentSessionId ? readSkillSessionSnapshotIfExists(options.parentSessionId, options) : null;
46867
47053
  if (!session && options.parentSessionId && !parentState) {
46868
47054
  throw new SkillSelectionError("SESSION_PARENT_NOT_FOUND", "A child Skills session requires an existing parent receipt so its inherited pin can be bound exactly.");
@@ -47000,7 +47186,7 @@ async function executeSelectedLocal(selected, options = {}) {
47000
47186
  throw new SkillSelectionError("INVALID_SECRET_BINDINGS", "Explicit environment values must be bounded strings without NUL bytes.");
47001
47187
  secretEnv[name] = value;
47002
47188
  }
47003
- const runDirectory = mkdtempSync3(join32(tmpdir(), "skills-execution-"));
47189
+ const runDirectory = mkdtempSync3(join33(tmpdir(), "skills-execution-"));
47004
47190
  const paths = new SkillEntryPaths;
47005
47191
  for (const entry of entries) {
47006
47192
  paths.add(entry.path, 100, () => {
@@ -47008,12 +47194,12 @@ async function executeSelectedLocal(selected, options = {}) {
47008
47194
  }, () => {
47009
47195
  throw new SkillSelectionError("INVALID_BUNDLE_PATH", "The execution bundle path exceeds its limit.");
47010
47196
  });
47011
- const destination = join32(runDirectory, entry.path);
47197
+ const destination = join33(runDirectory, entry.path);
47012
47198
  mkdirSync10(dirname20(destination), { recursive: true, mode: 448 });
47013
47199
  writeFileSync9(destination, entry.bytes, { flag: "wx", mode: entry.mode & 511 });
47014
47200
  }
47015
47201
  env.SKILLS_INPUT_JSON = input;
47016
- env.SKILLS_WORKSPACE_DIR = resolve18(options.cwd ?? process.cwd());
47202
+ env.SKILLS_WORKSPACE_DIR = resolve19(options.cwd ?? process.cwd());
47017
47203
  env.SKILLS_RUN_DIR = runDirectory;
47018
47204
  if (runtime.version) {
47019
47205
  const version = await subprocess([executable, ...runtimeName === "bun" ? ["--no-env-file"] : [], "--version"], runDirectory, env, "", Math.min(timeoutMs, 5000));
@@ -47026,7 +47212,7 @@ async function executeSelectedLocal(selected, options = {}) {
47026
47212
  const { authority: authority2, workspaceId, profileRevision, slug, version, bundleDigest } = selection2;
47027
47213
  const request2 = {
47028
47214
  selection: { authority: authority2, workspaceId, profileId, profileRevision, slug, version, bundleDigest },
47029
- consumer: { stationId: process.env.HASNA_STATION || stationHostname2(), workspaceDirectory: realpathSync11(options.cwd ?? process.cwd()) }
47215
+ consumer: { stationId: process.env.HASNA_STATION || stationHostname2(), workspaceDirectory: realpathSync12(options.cwd ?? process.cwd()) }
47030
47216
  };
47031
47217
  const grant = await (options.resolveExecutionGrant ?? resolveExecutionGrant)(request2);
47032
47218
  if (!grant || !grantIdentifier(grant.policyRevision) || !grantIdentifier(grant.grantId))
@@ -47036,7 +47222,7 @@ async function executeSelectedLocal(selected, options = {}) {
47036
47222
  }
47037
47223
  if (bindings)
47038
47224
  secretEnv = await resolveSelectedSecrets(bindings, options.createSecretsClient);
47039
- const result = await subprocess([executable, ...runtimeName === "bun" ? ["--no-env-file"] : [], join32(runDirectory, declaredEntry), ...args], runDirectory, { ...env, ...secretEnv }, input, timeoutMs);
47225
+ const result = await subprocess([executable, ...runtimeName === "bun" ? ["--no-env-file"] : [], join33(runDirectory, declaredEntry), ...args], runDirectory, { ...env, ...secretEnv }, input, timeoutMs);
47040
47226
  result.stdout = redactExecutionSecrets(result.stdout, secretEnv);
47041
47227
  result.stderr = redactExecutionSecrets(result.stderr, secretEnv);
47042
47228
  const receipt = {
@@ -47049,7 +47235,7 @@ async function executeSelectedLocal(selected, options = {}) {
47049
47235
  ...bindings ? { secretBinding: { schema: bindings.schema, selection: bindings.selection, consumer: bindings.consumer, secretsAuthority: bindings.secretsAuthority, bindings: bindings.bindings } } : {},
47050
47236
  ...result
47051
47237
  };
47052
- writeFileSync9(join32(runDirectory, ".execution-receipt.json"), JSON.stringify({ ...receipt, stdout: undefined, stderr: undefined }), { mode: 384 });
47238
+ writeFileSync9(join33(runDirectory, ".execution-receipt.json"), JSON.stringify({ ...receipt, stdout: undefined, stderr: undefined }), { mode: 384 });
47053
47239
  return receipt;
47054
47240
  }
47055
47241
  async function subprocess(command, cwd, env, input, timeoutMs) {
@@ -57114,7 +57300,7 @@ import { mkdirSync as mkdirSync12 } from "fs";
57114
57300
  import { dirname as dirname24 } from "path";
57115
57301
 
57116
57302
  // src/server/database-url.ts
57117
- import { isAbsolute as isAbsolute19, join as join34 } from "path";
57303
+ import { isAbsolute as isAbsolute19, join as join35 } from "path";
57118
57304
  import { fileURLToPath as fileURLToPath3 } from "url";
57119
57305
  var DEFAULT_SQLITE_FILENAME2 = "server.db";
57120
57306
  var SQLITE_MEMORY_PATH = ":memory:";
@@ -57123,7 +57309,7 @@ var SQLITE_SCHEMES = new Set(["sqlite", "sqlite3", "file"]);
57123
57309
  var MEMORY_SCHEMES = new Set(["memory"]);
57124
57310
  var SQLITE_EXTENSIONS = [".db", ".sqlite", ".sqlite3", ".db3"];
57125
57311
  function defaultSqlitePath() {
57126
- return join34(getDataDir(), DEFAULT_SQLITE_FILENAME2);
57312
+ return join35(getDataDir(), DEFAULT_SQLITE_FILENAME2);
57127
57313
  }
57128
57314
  function resolveDatabaseTarget(raw) {
57129
57315
  const value = raw?.trim();
@@ -57150,7 +57336,7 @@ function resolveDatabaseTarget(raw) {
57150
57336
  throw new Error(`unsupported database scheme "${scheme}:". Supported: postgres://, postgresql://, sqlite:, file:, ` + `an absolute or relative path to a .db/.sqlite file, ":memory:", or "memory:" (non-durable, tests only). ` + `Leave the setting empty to use the default SQLite database at ${defaultSqlitePath()}.`);
57151
57337
  }
57152
57338
  if (looksLikeSqlitePath(value)) {
57153
- const path = isAbsolute19(value) ? value : join34(process.cwd(), value);
57339
+ const path = isAbsolute19(value) ? value : join35(process.cwd(), value);
57154
57340
  return { kind: "sqlite", path, durable: true, label: `sqlite (${path})` };
57155
57341
  }
57156
57342
  throw new Error(`could not resolve a database backend from "${value}". Use postgres://\u2026, sqlite:\u2026, an absolute or ` + `relative path ending in ${SQLITE_EXTENSIONS.join("/")}, ":memory:", or leave it empty for the ` + `default SQLite database at ${defaultSqlitePath()}.`);
@@ -57174,7 +57360,7 @@ function sqlitePathFromUrl(value, scheme) {
57174
57360
  }
57175
57361
  return rest.slice(2).replace(/^\/\/+/, "/");
57176
57362
  }
57177
- return isAbsolute19(rest) ? rest : join34(process.cwd(), rest);
57363
+ return isAbsolute19(rest) ? rest : join35(process.cwd(), rest);
57178
57364
  }
57179
57365
  function looksLikeSqlitePath(value) {
57180
57366
  if (value.includes("/"))
@@ -57407,7 +57593,7 @@ class PostgresSkillSelectionStore {
57407
57593
  // src/server/sqlite-store.ts
57408
57594
  import { randomUUID as randomUUID7 } from "crypto";
57409
57595
  import { mkdirSync as mkdirSync11, readFileSync as readFileSync23, readdirSync as readdirSync13 } from "fs";
57410
- import { dirname as dirname23, join as join36 } from "path";
57596
+ import { dirname as dirname23, join as join37 } from "path";
57411
57597
 
57412
57598
  // src/server/auth.ts
57413
57599
  import { createHash as createHash23 } from "crypto";
@@ -57465,16 +57651,16 @@ function permitsSkillsRoute(principal, method, resource) {
57465
57651
  }
57466
57652
 
57467
57653
  // src/server/migrations-dir.ts
57468
- import { existsSync as existsSync15 } from "fs";
57469
- import { dirname as dirname22, join as join35 } from "path";
57654
+ import { existsSync as existsSync16 } from "fs";
57655
+ import { dirname as dirname22, join as join36 } from "path";
57470
57656
  var MIGRATION_DIALECTS = ["postgres", "sqlite"];
57471
57657
  var MAX_WALK_UP = 6;
57472
57658
  function findMigrationsRoot(startDirs = defaultStartDirs()) {
57473
57659
  for (const start of startDirs) {
57474
57660
  let dir = start;
57475
57661
  for (let level = 0;level < MAX_WALK_UP; level += 1) {
57476
- const candidate2 = join35(dir, "migrations");
57477
- if (MIGRATION_DIALECTS.some((dialect) => existsSync15(join35(candidate2, dialect))))
57662
+ const candidate2 = join36(dir, "migrations");
57663
+ if (MIGRATION_DIALECTS.some((dialect) => existsSync16(join36(candidate2, dialect))))
57478
57664
  return candidate2;
57479
57665
  const parent = dirname22(dir);
57480
57666
  if (parent === dir)
@@ -57488,8 +57674,8 @@ function resolveMigrationsDir(dialect, root4 = findMigrationsRoot()) {
57488
57674
  if (!root4) {
57489
57675
  throw new Error(`could not locate the migrations directory for dialect "${dialect}". ` + `Expected a migrations/${dialect}/ folder alongside the package root.`);
57490
57676
  }
57491
- const dir = join35(root4, dialect);
57492
- if (!existsSync15(dir)) {
57677
+ const dir = join36(root4, dialect);
57678
+ if (!existsSync16(dir)) {
57493
57679
  throw new Error(`migrations directory not found: ${dir}`);
57494
57680
  }
57495
57681
  return dir;
@@ -58460,7 +58646,7 @@ function applySqliteMigrations(db, migrationsDir = resolveMigrationsDir("sqlite"
58460
58646
  const appliedNow = [];
58461
58647
  for (const file of files) {
58462
58648
  const version2 = file.replace(/\.sql$/, "");
58463
- const text2 = readFileSync23(join36(migrationsDir, file), "utf8");
58649
+ const text2 = readFileSync23(join37(migrationsDir, file), "utf8");
58464
58650
  const apply = db.transaction(() => {
58465
58651
  const already = db.query("SELECT 1 AS present FROM schema_migrations WHERE version = ? LIMIT 1").get(version2);
58466
58652
  if (already)
@@ -90717,10 +90903,10 @@ async function readQuoteUnavailableCode(response) {
90717
90903
  let timer;
90718
90904
  let deadlineExceeded = false;
90719
90905
  const expired = Symbol("quote body deadline");
90720
- const deadline = new Promise((resolve20) => {
90906
+ const deadline = new Promise((resolve21) => {
90721
90907
  timer = setTimeout(() => {
90722
90908
  deadlineExceeded = true;
90723
- resolve20(expired);
90909
+ resolve21(expired);
90724
90910
  reader.cancel().catch(() => {});
90725
90911
  }, 1500);
90726
90912
  });
@@ -92206,12 +92392,12 @@ class RemotePrivatePublicationsClient {
92206
92392
  previous = view;
92207
92393
  if (!["queued", "verifying"].includes(view.state) || Date.now() >= until)
92208
92394
  return view;
92209
- await new Promise((resolve20) => {
92395
+ await new Promise((resolve21) => {
92210
92396
  const timer = setTimeout(done, Math.min(1000, until - Date.now()));
92211
92397
  function done() {
92212
92398
  clearTimeout(timer);
92213
92399
  options.signal?.removeEventListener("abort", done);
92214
- resolve20();
92400
+ resolve21();
92215
92401
  }
92216
92402
  options.signal?.addEventListener("abort", done, { once: true });
92217
92403
  });
@@ -92443,23 +92629,23 @@ class RemoteSkillsAuthClient {
92443
92629
  }
92444
92630
  }
92445
92631
  // src/lib/private-publication-recovery.ts
92446
- import { constants as constants13, closeSync as closeSync17, fsyncSync as fsyncSync5, fstatSync as fstatSync17, lstatSync as lstatSync23, mkdirSync as mkdirSync14, openSync as openSync17, readSync as readSync12, realpathSync as realpathSync12, renameSync as renameSync6, unlinkSync as unlinkSync5, writeFileSync as writeFileSync10 } from "fs";
92447
- import { dirname as dirname26, isAbsolute as isAbsolute20, join as join38, resolve as resolve20 } from "path";
92632
+ import { constants as constants13, closeSync as closeSync17, fsyncSync as fsyncSync5, fstatSync as fstatSync17, lstatSync as lstatSync24, mkdirSync as mkdirSync14, openSync as openSync17, readSync as readSync12, realpathSync as realpathSync13, renameSync as renameSync6, unlinkSync as unlinkSync5, writeFileSync as writeFileSync10 } from "fs";
92633
+ import { dirname as dirname26, isAbsolute as isAbsolute20, join as join39, resolve as resolve21 } from "path";
92448
92634
  import { randomUUID as randomUUID11 } from "crypto";
92449
92635
  var fail = () => {
92450
92636
  throw new PrivatePublicationError("PUBLICATION_RECOVERY_INVALID", "The recovery directory is invalid or changed. Preserve it and inspect the existing intent; do not start a replacement automatically.");
92451
92637
  };
92452
92638
  function safeDirectory(directory) {
92453
- if (!isAbsolute20(directory) || directory !== resolve20(directory) || realpathSync12(directory) !== directory)
92639
+ if (!isAbsolute20(directory) || directory !== resolve21(directory) || realpathSync13(directory) !== directory)
92454
92640
  return fail();
92455
92641
  for (let path2 = directory;; path2 = dirname26(path2)) {
92456
- const stat2 = lstatSync23(path2);
92642
+ const stat2 = lstatSync24(path2);
92457
92643
  if (!stat2.isDirectory() || stat2.isSymbolicLink())
92458
92644
  return fail();
92459
92645
  if (path2 === dirname26(path2))
92460
92646
  break;
92461
92647
  }
92462
- const own2 = lstatSync23(directory);
92648
+ const own2 = lstatSync24(directory);
92463
92649
  if ((own2.mode & 63) !== 0 || process.getuid && own2.uid !== process.getuid())
92464
92650
  return fail();
92465
92651
  return { dev: own2.dev, ino: own2.ino };
@@ -92470,7 +92656,7 @@ function unchangedDirectory(directory, identity4) {
92470
92656
  return fail();
92471
92657
  }
92472
92658
  function readOwned(directory, name, max) {
92473
- const identity4 = safeDirectory(directory), file2 = join38(directory, name);
92659
+ const identity4 = safeDirectory(directory), file2 = join39(directory, name);
92474
92660
  const fd = openSync17(file2, constants13.O_RDONLY | constants13.O_NOFOLLOW);
92475
92661
  try {
92476
92662
  const stat2 = fstatSync17(fd);
@@ -92494,7 +92680,7 @@ function readOwned(directory, name, max) {
92494
92680
  }
92495
92681
  }
92496
92682
  function writeOwned(directory, name, bytes) {
92497
- const fd = openSync17(join38(directory, name), constants13.O_WRONLY | constants13.O_CREAT | constants13.O_EXCL | constants13.O_NOFOLLOW, 384);
92683
+ const fd = openSync17(join39(directory, name), constants13.O_WRONLY | constants13.O_CREAT | constants13.O_EXCL | constants13.O_NOFOLLOW, 384);
92498
92684
  try {
92499
92685
  writeFileSync10(fd, bytes);
92500
92686
  fsyncSync5(fd);
@@ -92507,7 +92693,7 @@ function save(directory, value) {
92507
92693
  writeOwned(directory, temporary, JSON.stringify(value) + `
92508
92694
  `);
92509
92695
  unchangedDirectory(directory, identity4);
92510
- renameSync6(join38(directory, temporary), join38(directory, "receipt.json"));
92696
+ renameSync6(join39(directory, temporary), join39(directory, "receipt.json"));
92511
92697
  const fd = openSync17(directory, constants13.O_RDONLY | constants13.O_NOFOLLOW);
92512
92698
  try {
92513
92699
  fsyncSync5(fd);
@@ -92520,7 +92706,7 @@ function bind(client2, receipt) {
92520
92706
  throw new PrivatePublicationError("PUBLICATION_IDENTITY_CHANGED", "The fresh session does not match the recovery directory's server, account and membership.");
92521
92707
  }
92522
92708
  async function locked(directory, action) {
92523
- const identity4 = safeDirectory(directory), file2 = join38(directory, "operation.lock");
92709
+ const identity4 = safeDirectory(directory), file2 = join39(directory, "operation.lock");
92524
92710
  let fd;
92525
92711
  try {
92526
92712
  fd = openSync17(file2, constants13.O_WRONLY | constants13.O_CREAT | constants13.O_EXCL | constants13.O_NOFOLLOW, 384);
@@ -92536,7 +92722,7 @@ async function locked(directory, action) {
92536
92722
  } finally {
92537
92723
  closeSync17(fd);
92538
92724
  unchangedDirectory(directory, identity4);
92539
- const now2 = lstatSync23(file2);
92725
+ const now2 = lstatSync24(file2);
92540
92726
  if (now2.dev !== lock.dev || now2.ino !== lock.ino || !now2.isFile() || now2.isSymbolicLink())
92541
92727
  fail();
92542
92728
  unlinkSync5(file2);
@@ -92588,7 +92774,7 @@ async function preparePrivatePublication(client2, sourceDirectory, recoveryDirec
92588
92774
  phase: "prepared",
92589
92775
  intent: null
92590
92776
  };
92591
- if (!isAbsolute20(recoveryDirectory) || resolve20(recoveryDirectory) !== recoveryDirectory || realpathSync12(dirname26(recoveryDirectory)) !== dirname26(recoveryDirectory))
92777
+ if (!isAbsolute20(recoveryDirectory) || resolve21(recoveryDirectory) !== recoveryDirectory || realpathSync13(dirname26(recoveryDirectory)) !== dirname26(recoveryDirectory))
92592
92778
  return fail();
92593
92779
  mkdirSync14(recoveryDirectory, { mode: 448 });
92594
92780
  safeDirectory(recoveryDirectory);