@skillrecordings/cli 0.14.3 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1479,9 +1479,9 @@ var require_url_state_machine = __commonJS({
1479
1479
  url.username += percentEncodeChar(decoded[i], isUserinfoPercentEncode);
1480
1480
  }
1481
1481
  };
1482
- module.exports.setThePassword = function(url, password) {
1482
+ module.exports.setThePassword = function(url, password3) {
1483
1483
  url.password = "";
1484
- const decoded = punycode.ucs2.decode(password);
1484
+ const decoded = punycode.ucs2.decode(password3);
1485
1485
  for (let i = 0; i < decoded.length; ++i) {
1486
1486
  url.password += percentEncodeChar(decoded[i], isUserinfoPercentEncode);
1487
1487
  }
@@ -16736,7 +16736,7 @@ var require_proxy_agent = __commonJS({
16736
16736
  const { proxyTunnel = true } = opts;
16737
16737
  super();
16738
16738
  const url = this.#getUrl(opts);
16739
- const { href, origin, port, protocol, username, password, hostname: proxyHostname } = url;
16739
+ const { href, origin, port, protocol, username, password: password3, hostname: proxyHostname } = url;
16740
16740
  this[kProxy] = { uri: href, protocol };
16741
16741
  this[kRequestTls] = opts.requestTls;
16742
16742
  this[kProxyTls] = opts.proxyTls;
@@ -16748,8 +16748,8 @@ var require_proxy_agent = __commonJS({
16748
16748
  this[kProxyHeaders]["proxy-authorization"] = `Basic ${opts.auth}`;
16749
16749
  } else if (opts.token) {
16750
16750
  this[kProxyHeaders]["proxy-authorization"] = opts.token;
16751
- } else if (username && password) {
16752
- this[kProxyHeaders]["proxy-authorization"] = `Basic ${Buffer.from(`${decodeURIComponent(username)}:${decodeURIComponent(password)}`).toString("base64")}`;
16751
+ } else if (username && password3) {
16752
+ this[kProxyHeaders]["proxy-authorization"] = `Basic ${Buffer.from(`${decodeURIComponent(username)}:${decodeURIComponent(password3)}`).toString("base64")}`;
16753
16753
  }
16754
16754
  const connect = buildConnector({ ...opts.proxyTls });
16755
16755
  this[kConnectEndpoint] = buildConnector({ ...opts.requestTls });
@@ -19843,7 +19843,7 @@ var require_snapshot_recorder = __commonJS({
19843
19843
  "use strict";
19844
19844
  init_esm_shims();
19845
19845
  var { writeFile: writeFile9, readFile: readFile10, mkdir: mkdir2 } = __require("fs/promises");
19846
- var { dirname: dirname8, resolve: resolve9 } = __require("path");
19846
+ var { dirname: dirname7, resolve: resolve9 } = __require("path");
19847
19847
  var { setTimeout: setTimeout2, clearTimeout: clearTimeout2 } = __require("timers");
19848
19848
  var { InvalidArgumentError, UndiciError } = require_errors();
19849
19849
  var { hashId, isUrlExcludedFactory, normalizeHeaders, createHeaderFilters } = require_snapshot_utils();
@@ -20074,7 +20074,7 @@ var require_snapshot_recorder = __commonJS({
20074
20074
  throw new InvalidArgumentError("Snapshot path is required");
20075
20075
  }
20076
20076
  const resolvedPath = resolve9(path);
20077
- await mkdir2(dirname8(resolvedPath), { recursive: true });
20077
+ await mkdir2(dirname7(resolvedPath), { recursive: true });
20078
20078
  const data2 = Array.from(this.#snapshots.entries()).map(([hash, snapshot]) => ({
20079
20079
  hash,
20080
20080
  snapshot
@@ -26406,8 +26406,8 @@ var require_fetch = __commonJS({
26406
26406
  let authorizationValue = null;
26407
26407
  if (hasAuthenticationEntry(httpRequest) && (httpRequest.useURLCredentials === void 0 || !includesCredentials(requestCurrentURL(httpRequest)))) {
26408
26408
  } else if (includesCredentials(requestCurrentURL(httpRequest)) && isAuthenticationFetch) {
26409
- const { username, password } = requestCurrentURL(httpRequest);
26410
- authorizationValue = `Basic ${Buffer.from(`${username}:${password}`).toString("base64")}`;
26409
+ const { username, password: password3 } = requestCurrentURL(httpRequest);
26410
+ authorizationValue = `Basic ${Buffer.from(`${username}:${password3}`).toString("base64")}`;
26411
26411
  }
26412
26412
  if (authorizationValue !== null) {
26413
26413
  httpRequest.headersList.append("Authorization", authorizationValue, false);
@@ -74714,9 +74714,9 @@ init_esm_shims();
74714
74714
  var ABBREVIATED_THRESHOLD = 2;
74715
74715
  var MINIMAL_THRESHOLD = 5;
74716
74716
  var ROOT_DESCRIPTIONS = {
74717
- full: "Skill Recordings support agent CLI \u2014 triage, investigate, and manage customer conversations.\n\n Getting Started:\n 1. skill auth setup Configure 1Password secrets (Front API token, DB, etc.)\n 2. skill auth status Verify your credentials are working\n 3. skill front inbox See what needs attention right now\n\n Common Workflows:\n Triage inbox skill front inbox \u2192 skill front triage\n Investigate ticket skill front conversation <id> --messages\n Bulk cleanup skill front bulk-archive --older-than 30d\n Generate report skill front report --inbox support\n Check deploys skill deploys\n\n For AI Agents (Claude Code, MCP):\n skill mcp Start JSON-RPC server with 9 Front tools\n skill plugin sync Install the Claude Code plugin\n All commands support --json for structured, HATEOAS-enriched output",
74718
- abbreviated: "Skill Recordings support agent CLI \u2014 triage and investigate support conversations.\n\n Start here:\n skill auth setup Configure 1Password + secrets\n skill front inbox See what needs attention\n skill front triage Auto-categorize conversations\n\n Common:\n skill front conversation <id> --messages\n skill front reply <id>\n skill deploys\n skill mcp\n",
74719
- minimal: "Skill Recordings support agent CLI. Try: skill front inbox, skill front triage, skill auth status. Use --help for details."
74717
+ full: "Skill Recordings support agent CLI \u2014 triage, investigate, and manage customer conversations.\n\n Getting Started:\n 1. skill wizard Interactive app setup wizard\n 2. skill keys Manage your personal API keys\n 3. skill front inbox See what needs attention right now\n\n Common Workflows:\n Triage inbox skill front inbox \u2192 skill front triage\n Investigate ticket skill front conversation <id> --messages\n Bulk cleanup skill front bulk-archive --older-than 30d\n Generate report skill front report --inbox support\n Check deploys skill deploys\n\n For AI Agents (Claude Code, MCP):\n skill mcp Start JSON-RPC server with 9 Front tools\n skill plugin sync Install the Claude Code plugin\n All commands support --json for structured, HATEOAS-enriched output",
74718
+ abbreviated: "Skill Recordings support agent CLI \u2014 triage and investigate support conversations.\n\n Start here:\n skill wizard Set up a new product\n skill keys Manage API keys\n skill front inbox See what needs attention\n skill front triage Auto-categorize conversations\n\n Common:\n skill front conversation <id> --messages\n skill front reply <id>\n skill deploys\n skill mcp\n",
74719
+ minimal: "Skill Recordings support agent CLI. Try: skill wizard, skill keys, skill front inbox, skill front triage. Use --help for details."
74720
74720
  };
74721
74721
  var FRONT_DESCRIPTIONS = {
74722
74722
  full: "Front conversations, inboxes, tags, archival, and reporting.\n\n Prerequisites:\n FRONT_API_TOKEN must be set. Run: skill auth setup\n\n Start here:\n skill front inbox See unassigned conversations\n skill front inbox support List conversations in a specific inbox\n skill front triage AI-powered categorization of inbox items\n\n Investigate a conversation:\n skill front conversation <id> -m Full conversation with messages\n skill front message <id> Single message details + body\n\n Take action:\n skill front assign <id> Assign to a teammate\n skill front reply <id> Draft a reply (HITL, never auto-sends)\n skill front tag <id> Add a tag\n skill front archive <id> Archive a resolved conversation\n\n Bulk operations:\n skill front bulk-archive Archive old/spam conversations\n skill front report Volume + tag + sender forensics\n\n All commands accept --json for HATEOAS-enriched output with _links and _actions.",
@@ -76954,11 +76954,11 @@ Saved to ${options.output}`);
76954
76954
  }
76955
76955
  }
76956
76956
  async function toEvalite(options) {
76957
- const { readFileSync: readFileSync12 } = await import("fs");
76957
+ const { readFileSync: readFileSync13 } = await import("fs");
76958
76958
  const { ctx } = options;
76959
76959
  const outputJson = ctx.format === "json";
76960
76960
  const data2 = JSON.parse(
76961
- readFileSync12(options.input, "utf-8")
76961
+ readFileSync13(options.input, "utf-8")
76962
76962
  );
76963
76963
  const evaliteData = data2.map((d) => ({
76964
76964
  input: d.triggerMessage.body,
@@ -77019,15 +77019,19 @@ init_esm_shims();
77019
77019
 
77020
77020
  // src/commands/config/get.ts
77021
77021
  init_esm_shims();
77022
- import { existsSync as existsSync5, readFileSync as readFileSync3 } from "fs";
77022
+ import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
77023
77023
  import { Decrypter as Decrypter2 } from "age-encryption";
77024
77024
 
77025
+ // src/commands/config/set.ts
77026
+ init_esm_shims();
77027
+ import { existsSync as existsSync3, readFileSync as readFileSync2, writeFileSync as writeFileSync3 } from "fs";
77028
+ import { password, select as select2 } from "@inquirer/prompts";
77029
+ import { Decrypter, Encrypter, identityToRecipient } from "age-encryption";
77030
+
77025
77031
  // src/commands/config/init.ts
77026
77032
  init_esm_shims();
77027
- import { existsSync as existsSync3, mkdirSync, writeFileSync as writeFileSync3 } from "fs";
77028
77033
  import { homedir as homedir2 } from "os";
77029
77034
  import { join as join2 } from "path";
77030
- import { generateIdentity, identityToRecipient } from "age-encryption";
77031
77035
  function getUserConfigDir2() {
77032
77036
  return join2(homedir2(), ".config", "skill");
77033
77037
  }
@@ -77036,67 +77040,27 @@ function getAgeKeyPath() {
77036
77040
  }
77037
77041
  async function configInitAction(ctx, options = {}) {
77038
77042
  const outputJson = options.json === true || ctx.format === "json";
77039
- const keyPath = getAgeKeyPath();
77040
- const configDir = getUserConfigDir2();
77041
- if (existsSync3(keyPath) && !options.force) {
77042
- const result = {
77043
- success: false,
77044
- error: `Age key already exists at ${keyPath}. Use --force to overwrite.`
77045
- };
77046
- if (outputJson) {
77047
- ctx.output.data(result);
77048
- } else {
77049
- ctx.output.error(result.error);
77050
- ctx.output.data(`
77051
- To view your public key: skill config public-key`);
77052
- }
77053
- process.exitCode = EXIT_CODES.usage;
77054
- return;
77055
- }
77056
- try {
77057
- if (!existsSync3(configDir)) {
77058
- mkdirSync(configDir, { recursive: true, mode: 448 });
77059
- }
77060
- const identity = await generateIdentity();
77061
- const recipient = await identityToRecipient(identity);
77062
- writeFileSync3(keyPath, identity, { encoding: "utf8", mode: 384 });
77063
- const result = {
77064
- success: true,
77065
- keyPath,
77066
- publicKey: recipient
77067
- };
77068
- if (outputJson) {
77069
- ctx.output.data(result);
77070
- } else {
77071
- ctx.output.success("Age keypair generated successfully!");
77072
- ctx.output.data(`
77073
- Private key saved to: ${keyPath}`);
77074
- ctx.output.data(`Public key (age recipient): ${recipient}`);
77075
- ctx.output.data(
77076
- "\n\u26A0\uFE0F Keep your private key secure. Anyone with access can decrypt your config."
77077
- );
77078
- ctx.output.data("\nNext steps:");
77079
- ctx.output.data(" 1. Set config values: skill config set KEY=value");
77080
- ctx.output.data(" 2. View config: skill config list");
77081
- }
77082
- } catch (error) {
77083
- const result = {
77084
- success: false,
77085
- error: error instanceof Error ? error.message : "Failed to generate keypair"
77086
- };
77087
- if (outputJson) {
77088
- ctx.output.data(result);
77089
- } else {
77090
- ctx.output.error(`Failed to generate keypair: ${result.error}`);
77091
- }
77092
- process.exitCode = EXIT_CODES.error;
77043
+ const result = {
77044
+ success: false,
77045
+ error: "DEPRECATED: skill config init is no longer needed.\nThe CLI now uses the 1Password age key for encryption.\nUse `skill keys` to manage your personal API keys."
77046
+ };
77047
+ if (outputJson) {
77048
+ ctx.output.data(result);
77049
+ } else {
77050
+ ctx.output.error("\u26A0\uFE0F DEPRECATED: skill config init is no longer needed.");
77051
+ ctx.output.data("");
77052
+ ctx.output.data("The CLI now uses the 1Password age key for encryption.");
77053
+ ctx.output.data("Local age keypairs are no longer required.");
77054
+ ctx.output.data("");
77055
+ ctx.output.data("To manage your personal API keys:");
77056
+ ctx.output.data(" skill keys Interactive setup");
77057
+ ctx.output.data(" skill keys add Add a personal API key");
77058
+ ctx.output.data(" skill keys status Show key provenance");
77093
77059
  }
77060
+ process.exitCode = EXIT_CODES.usage;
77094
77061
  }
77095
77062
 
77096
77063
  // src/commands/config/set.ts
77097
- init_esm_shims();
77098
- import { existsSync as existsSync4, readFileSync as readFileSync2, writeFileSync as writeFileSync4 } from "fs";
77099
- import { Decrypter, Encrypter, identityToRecipient as identityToRecipient2 } from "age-encryption";
77100
77064
  function getEncryptedConfigPath() {
77101
77065
  return `${getUserConfigDir2()}/.env.user.encrypted`;
77102
77066
  }
@@ -77109,7 +77073,7 @@ function parseKeyValue(input2) {
77109
77073
  return { key, value };
77110
77074
  }
77111
77075
  async function readExistingConfig(identity, configPath) {
77112
- if (!existsSync4(configPath)) {
77076
+ if (!existsSync3(configPath)) {
77113
77077
  return {};
77114
77078
  }
77115
77079
  try {
@@ -77136,7 +77100,7 @@ async function readExistingConfig(identity, configPath) {
77136
77100
  async function configSetAction(ctx, keyValue, options = {}) {
77137
77101
  const outputJson = options.json === true || ctx.format === "json";
77138
77102
  const keyPath = getAgeKeyPath();
77139
- if (!existsSync4(keyPath)) {
77103
+ if (!existsSync3(keyPath)) {
77140
77104
  const result = {
77141
77105
  success: false,
77142
77106
  error: "Age key not found. Run: skill config init"
@@ -77149,7 +77113,29 @@ async function configSetAction(ctx, keyValue, options = {}) {
77149
77113
  process.exitCode = EXIT_CODES.usage;
77150
77114
  return;
77151
77115
  }
77152
- const parsed = parseKeyValue(keyValue);
77116
+ let finalKeyValue = keyValue;
77117
+ if (!finalKeyValue && process.stdin.isTTY && !outputJson) {
77118
+ try {
77119
+ const selectedKey = await select2({
77120
+ message: "Select a secret key to set:",
77121
+ choices: Object.keys(SECRET_REFS).map((key) => ({
77122
+ name: key,
77123
+ value: key
77124
+ }))
77125
+ });
77126
+ const secretValue = await password({
77127
+ message: `Enter value for ${selectedKey}:`
77128
+ });
77129
+ finalKeyValue = `${selectedKey}=${secretValue}`;
77130
+ } catch (error) {
77131
+ if (error instanceof Error && (error.message.includes("User force closed") || error.message.includes("canceled"))) {
77132
+ ctx.output.data("Cancelled");
77133
+ return;
77134
+ }
77135
+ throw error;
77136
+ }
77137
+ }
77138
+ const parsed = parseKeyValue(finalKeyValue || "");
77153
77139
  if (!parsed) {
77154
77140
  const result = {
77155
77141
  success: false,
@@ -77166,7 +77152,7 @@ async function configSetAction(ctx, keyValue, options = {}) {
77166
77152
  }
77167
77153
  try {
77168
77154
  const identity = readFileSync2(keyPath, "utf8").trim();
77169
- const recipient = await identityToRecipient2(identity);
77155
+ const recipient = await identityToRecipient(identity);
77170
77156
  const configPath = getEncryptedConfigPath();
77171
77157
  const config = await readExistingConfig(identity, configPath);
77172
77158
  config[parsed.key] = parsed.value;
@@ -77174,7 +77160,7 @@ async function configSetAction(ctx, keyValue, options = {}) {
77174
77160
  const encrypter = new Encrypter();
77175
77161
  encrypter.addRecipient(recipient);
77176
77162
  const encrypted = await encrypter.encrypt(envContent + "\n");
77177
- writeFileSync4(configPath, Buffer.from(encrypted));
77163
+ writeFileSync3(configPath, Buffer.from(encrypted));
77178
77164
  const result = {
77179
77165
  success: true,
77180
77166
  key: parsed.key,
@@ -77201,9 +77187,24 @@ async function configSetAction(ctx, keyValue, options = {}) {
77201
77187
  }
77202
77188
 
77203
77189
  // src/commands/config/get.ts
77190
+ async function getAgeKeyFrom1Password2() {
77191
+ if (!process.env.OP_SERVICE_ACCOUNT_TOKEN) {
77192
+ return null;
77193
+ }
77194
+ try {
77195
+ const { OnePasswordProvider: OnePasswordProvider2 } = await import("./secrets-MGVPGMFJ.js");
77196
+ const op = new OnePasswordProvider2();
77197
+ if (!await op.isAvailable()) {
77198
+ return null;
77199
+ }
77200
+ return await op.resolve("op://Support/skill-cli-age-key/private_key");
77201
+ } catch {
77202
+ return null;
77203
+ }
77204
+ }
77204
77205
  async function decryptConfig(identity) {
77205
77206
  const configPath = getEncryptedConfigPath();
77206
- if (!existsSync5(configPath)) {
77207
+ if (!existsSync4(configPath)) {
77207
77208
  return {};
77208
77209
  }
77209
77210
  const encrypted = readFileSync3(configPath);
@@ -77231,11 +77232,11 @@ async function decryptConfig(identity) {
77231
77232
  }
77232
77233
  async function configGetAction(ctx, key, options = {}) {
77233
77234
  const outputJson = options.json === true || ctx.format === "json";
77234
- const keyPath = getAgeKeyPath();
77235
- if (!existsSync5(keyPath)) {
77235
+ const identity = await getAgeKeyFrom1Password2();
77236
+ if (!identity) {
77236
77237
  const result = {
77237
77238
  success: false,
77238
- error: "Age key not found. Run: skill config init"
77239
+ error: "OP_SERVICE_ACCOUNT_TOKEN not set. Required for encrypted config."
77239
77240
  };
77240
77241
  if (outputJson) {
77241
77242
  ctx.output.data(result);
@@ -77246,7 +77247,6 @@ async function configGetAction(ctx, key, options = {}) {
77246
77247
  return;
77247
77248
  }
77248
77249
  try {
77249
- const identity = readFileSync3(keyPath, "utf8").trim();
77250
77250
  const config = await decryptConfig(identity);
77251
77251
  if (!(key in config)) {
77252
77252
  const result2 = {
@@ -77289,11 +77289,26 @@ async function configGetAction(ctx, key, options = {}) {
77289
77289
 
77290
77290
  // src/commands/config/list.ts
77291
77291
  init_esm_shims();
77292
- import { existsSync as existsSync6, readFileSync as readFileSync4 } from "fs";
77292
+ import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
77293
77293
  import { Decrypter as Decrypter3 } from "age-encryption";
77294
+ async function getAgeKeyFrom1Password3() {
77295
+ if (!process.env.OP_SERVICE_ACCOUNT_TOKEN) {
77296
+ return null;
77297
+ }
77298
+ try {
77299
+ const { OnePasswordProvider: OnePasswordProvider2 } = await import("./secrets-MGVPGMFJ.js");
77300
+ const op = new OnePasswordProvider2();
77301
+ if (!await op.isAvailable()) {
77302
+ return null;
77303
+ }
77304
+ return await op.resolve("op://Support/skill-cli-age-key/private_key");
77305
+ } catch {
77306
+ return null;
77307
+ }
77308
+ }
77294
77309
  async function decryptConfig2(identity) {
77295
77310
  const configPath = getEncryptedConfigPath();
77296
- if (!existsSync6(configPath)) {
77311
+ if (!existsSync5(configPath)) {
77297
77312
  return {};
77298
77313
  }
77299
77314
  const encrypted = readFileSync4(configPath);
@@ -77321,11 +77336,11 @@ async function decryptConfig2(identity) {
77321
77336
  }
77322
77337
  async function configListAction(ctx, options = {}) {
77323
77338
  const outputJson = options.json === true || ctx.format === "json";
77324
- const keyPath = getAgeKeyPath();
77325
- if (!existsSync6(keyPath)) {
77339
+ const identity = await getAgeKeyFrom1Password3();
77340
+ if (!identity) {
77326
77341
  const result = {
77327
77342
  success: false,
77328
- error: "Age key not found. Run: skill config init"
77343
+ error: "OP_SERVICE_ACCOUNT_TOKEN not set. Required for encrypted config."
77329
77344
  };
77330
77345
  if (outputJson) {
77331
77346
  ctx.output.data(result);
@@ -77336,7 +77351,6 @@ async function configListAction(ctx, options = {}) {
77336
77351
  return;
77337
77352
  }
77338
77353
  try {
77339
- const identity = readFileSync4(keyPath, "utf8").trim();
77340
77354
  const config = await decryptConfig2(identity);
77341
77355
  const keys = Object.keys(config);
77342
77356
  if (keys.length === 0) {
@@ -77401,11 +77415,13 @@ var buildContext2 = async (command, json) => {
77401
77415
  };
77402
77416
  function registerConfigCommands(program3) {
77403
77417
  const config = program3.command("config").description("Manage user-specific config overrides (encrypted)");
77404
- config.command("init").description("Generate age keypair for user config encryption").option("--force", "Overwrite existing keypair").option("--json", "Output as JSON").action(async (options, command) => {
77418
+ config.command("init").description("[DEPRECATED] No longer needed - use `skill keys` instead").option("--force", "Overwrite existing keypair").option("--json", "Output as JSON").action(async (options, command) => {
77405
77419
  const ctx = await buildContext2(command, options.json);
77406
77420
  await configInitAction(ctx, options);
77407
77421
  });
77408
- config.command("set <key-value>").description("Set encrypted config value (format: KEY=value)").option("--json", "Output as JSON").action(async (keyValue, options, command) => {
77422
+ config.command("set [key-value]").description(
77423
+ "Set encrypted config value (format: KEY=value or interactive)"
77424
+ ).option("--json", "Output as JSON").action(async (keyValue, options, command) => {
77409
77425
  const ctx = await buildContext2(command, options.json);
77410
77426
  await configSetAction(ctx, keyValue, options);
77411
77427
  });
@@ -80089,7 +80105,7 @@ init_esm_shims();
80089
80105
  // src/commands/eval-pipeline/run.ts
80090
80106
  init_esm_shims();
80091
80107
  import { createHash as createHash2 } from "crypto";
80092
- import { existsSync as existsSync7, mkdirSync as mkdirSync2, readFileSync as readFileSync5, rmSync, writeFileSync as writeFileSync5 } from "fs";
80108
+ import { existsSync as existsSync6, mkdirSync, readFileSync as readFileSync5, rmSync, writeFileSync as writeFileSync4 } from "fs";
80093
80109
  import { join as join5 } from "path";
80094
80110
  import { readFile as readFile6 } from "fs/promises";
80095
80111
  import { glob as glob4 } from "glob";
@@ -80507,7 +80523,7 @@ function getClassifySourceHash() {
80507
80523
  join5(process.cwd(), "../core/src/pipeline/classify.ts")
80508
80524
  ];
80509
80525
  for (const path of possiblePaths) {
80510
- if (existsSync7(path)) {
80526
+ if (existsSync6(path)) {
80511
80527
  const content = readFileSync5(path, "utf-8");
80512
80528
  return createHash2("md5").update(content).digest("hex");
80513
80529
  }
@@ -80519,7 +80535,7 @@ function getClassifySourceHash() {
80519
80535
  function loadCachedClassify(cacheKey) {
80520
80536
  const cachePath = join5(CACHE_DIR, `${cacheKey}.json`);
80521
80537
  try {
80522
- if (existsSync7(cachePath)) {
80538
+ if (existsSync6(cachePath)) {
80523
80539
  return JSON.parse(readFileSync5(cachePath, "utf-8"));
80524
80540
  }
80525
80541
  } catch {
@@ -80528,17 +80544,17 @@ function loadCachedClassify(cacheKey) {
80528
80544
  }
80529
80545
  function saveCachedClassify(cacheKey, result) {
80530
80546
  try {
80531
- if (!existsSync7(CACHE_DIR)) {
80532
- mkdirSync2(CACHE_DIR, { recursive: true });
80547
+ if (!existsSync6(CACHE_DIR)) {
80548
+ mkdirSync(CACHE_DIR, { recursive: true });
80533
80549
  }
80534
80550
  const cachePath = join5(CACHE_DIR, `${cacheKey}.json`);
80535
- writeFileSync5(cachePath, JSON.stringify(result));
80551
+ writeFileSync4(cachePath, JSON.stringify(result));
80536
80552
  } catch {
80537
80553
  }
80538
80554
  }
80539
80555
  function clearClassifyCache() {
80540
80556
  try {
80541
- if (existsSync7(CACHE_DIR)) {
80557
+ if (existsSync6(CACHE_DIR)) {
80542
80558
  rmSync(CACHE_DIR, { recursive: true, force: true });
80543
80559
  }
80544
80560
  } catch {
@@ -81530,7 +81546,7 @@ function registerEvalPipelineCommands(program3) {
81530
81546
 
81531
81547
  // src/commands/eval-prompt.ts
81532
81548
  init_esm_shims();
81533
- import { existsSync as existsSync8, readFileSync as readFileSync6, writeFileSync as writeFileSync6 } from "fs";
81549
+ import { existsSync as existsSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
81534
81550
  import { generateText as generateText2, stepCountIs as stepCountIs2, tool as tool4 } from "ai";
81535
81551
  import { z as z5 } from "zod";
81536
81552
  var leakPatterns = [
@@ -81717,7 +81733,7 @@ async function runEval2(ctx, options) {
81717
81733
  try {
81718
81734
  let prompt = SUPPORT_AGENT_PROMPT;
81719
81735
  if (promptPath) {
81720
- if (!existsSync8(promptPath)) {
81736
+ if (!existsSync7(promptPath)) {
81721
81737
  throw new CLIError({
81722
81738
  userMessage: `Prompt file not found: ${promptPath}.`,
81723
81739
  suggestion: "Verify the prompt path and try again."
@@ -81730,7 +81746,7 @@ async function runEval2(ctx, options) {
81730
81746
  } else if (!outputJson) {
81731
81747
  ctx.output.message("Using production prompt");
81732
81748
  }
81733
- if (!existsSync8(datasetPath)) {
81749
+ if (!existsSync7(datasetPath)) {
81734
81750
  throw new CLIError({
81735
81751
  userMessage: `Dataset not found: ${datasetPath}.`,
81736
81752
  suggestion: "Provide a valid dataset file path."
@@ -81813,7 +81829,7 @@ async function runEval2(ctx, options) {
81813
81829
  });
81814
81830
  }
81815
81831
  if (outputPath) {
81816
- writeFileSync6(outputPath, JSON.stringify(results, null, 2));
81832
+ writeFileSync5(outputPath, JSON.stringify(results, null, 2));
81817
81833
  if (!outputJson) {
81818
81834
  ctx.output.success(`Saved results to ${outputPath}`);
81819
81835
  }
@@ -81842,7 +81858,7 @@ async function comparePrompts(ctx, options) {
81842
81858
  try {
81843
81859
  const baselinePrompt = baseline ? readFileSync6(baseline, "utf-8") : SUPPORT_AGENT_PROMPT;
81844
81860
  const candidatePrompt = readFileSync6(candidate, "utf-8");
81845
- if (!existsSync8(datasetPath)) {
81861
+ if (!existsSync7(datasetPath)) {
81846
81862
  throw new CLIError({
81847
81863
  userMessage: `Dataset not found: ${datasetPath}.`,
81848
81864
  suggestion: "Provide a valid dataset file path."
@@ -81990,8 +82006,8 @@ init_esm_shims();
81990
82006
 
81991
82007
  // src/commands/faq/classify.ts
81992
82008
  init_esm_shims();
81993
- import { appendFileSync, existsSync as existsSync9, mkdirSync as mkdirSync3, readFileSync as readFileSync7 } from "fs";
81994
- import { dirname as dirname3, join as join7, resolve as resolve3 } from "path";
82009
+ import { appendFileSync, existsSync as existsSync8, mkdirSync as mkdirSync2, readFileSync as readFileSync7 } from "fs";
82010
+ import { dirname as dirname2, join as join7, resolve as resolve3 } from "path";
81995
82011
  import { generateObject } from "ai";
81996
82012
  import { z as z6 } from "zod";
81997
82013
  var PROJECT_ROOT = resolve3(__dirname, "../../../..");
@@ -82058,7 +82074,7 @@ async function loadConversationsFromParquet(parquetPath) {
82058
82074
  }
82059
82075
  function loadExistingClassifications(outputPath) {
82060
82076
  const classifiedIds = /* @__PURE__ */ new Set();
82061
- if (!existsSync9(outputPath)) {
82077
+ if (!existsSync8(outputPath)) {
82062
82078
  return classifiedIds;
82063
82079
  }
82064
82080
  const content = readFileSync7(outputPath, "utf-8");
@@ -82176,7 +82192,7 @@ async function faqClassify(ctx, options) {
82176
82192
  ctx.output.data(` Dry run: ${options.dryRun ?? false}`);
82177
82193
  ctx.output.data("");
82178
82194
  }
82179
- if (!existsSync9(parquetPath)) {
82195
+ if (!existsSync8(parquetPath)) {
82180
82196
  handleFaqClassifyError(
82181
82197
  ctx,
82182
82198
  new CLIError({
@@ -82187,7 +82203,7 @@ async function faqClassify(ctx, options) {
82187
82203
  );
82188
82204
  return;
82189
82205
  }
82190
- if (!existsSync9(taxonomyPath)) {
82206
+ if (!existsSync8(taxonomyPath)) {
82191
82207
  handleFaqClassifyError(
82192
82208
  ctx,
82193
82209
  new CLIError({
@@ -82198,9 +82214,9 @@ async function faqClassify(ctx, options) {
82198
82214
  );
82199
82215
  return;
82200
82216
  }
82201
- const outputDir = dirname3(outputPath);
82202
- if (!existsSync9(outputDir)) {
82203
- mkdirSync3(outputDir, { recursive: true });
82217
+ const outputDir = dirname2(outputPath);
82218
+ if (!existsSync8(outputDir)) {
82219
+ mkdirSync2(outputDir, { recursive: true });
82204
82220
  }
82205
82221
  if (!outputJson) ctx.output.data("\u{1F4DA} Loading taxonomy...");
82206
82222
  const taxonomy = JSON.parse(readFileSync7(taxonomyPath, "utf-8"));
@@ -82368,18 +82384,18 @@ function registerFaqClassifyCommands(program3) {
82368
82384
 
82369
82385
  // src/commands/faq/cluster.ts
82370
82386
  init_esm_shims();
82371
- import { existsSync as existsSync11 } from "fs";
82387
+ import { existsSync as existsSync10 } from "fs";
82372
82388
  import { join as join9, resolve as resolve4 } from "path";
82373
82389
 
82374
82390
  // ../core/src/faq/production-clusterer.ts
82375
82391
  init_esm_shims();
82376
- import { existsSync as existsSync10, mkdirSync as mkdirSync4, readFileSync as readFileSync8, writeFileSync as writeFileSync7 } from "fs";
82392
+ import { existsSync as existsSync9, mkdirSync as mkdirSync3, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "fs";
82377
82393
  import { join as join8 } from "path";
82378
82394
  function readPhase0Assignments(phase0Path) {
82379
82395
  const assignmentsPath = join8(phase0Path, "clusters/v1/assignments.json");
82380
- if (!existsSync10(assignmentsPath)) {
82396
+ if (!existsSync9(assignmentsPath)) {
82381
82397
  const latestPath = join8(phase0Path, "clusters/latest/assignments.json");
82382
- if (!existsSync10(latestPath)) {
82398
+ if (!existsSync9(latestPath)) {
82383
82399
  throw new Error(`Phase 0 assignments not found at ${assignmentsPath}`);
82384
82400
  }
82385
82401
  const content2 = readFileSync8(latestPath, "utf-8");
@@ -82390,9 +82406,9 @@ function readPhase0Assignments(phase0Path) {
82390
82406
  }
82391
82407
  function readPhase0Labels(phase0Path) {
82392
82408
  const labelsPath = join8(phase0Path, "clusters/v1/labels.json");
82393
- if (!existsSync10(labelsPath)) {
82409
+ if (!existsSync9(labelsPath)) {
82394
82410
  const latestPath = join8(phase0Path, "clusters/latest/labels.json");
82395
- if (!existsSync10(latestPath)) {
82411
+ if (!existsSync9(latestPath)) {
82396
82412
  throw new Error(`Phase 0 labels not found at ${labelsPath}`);
82397
82413
  }
82398
82414
  const content2 = readFileSync8(latestPath, "utf-8");
@@ -82405,9 +82421,9 @@ function readPhase0Labels(phase0Path) {
82405
82421
  }
82406
82422
  function readPhase0Metrics(phase0Path) {
82407
82423
  const metricsPath = join8(phase0Path, "clusters/v1/metrics.json");
82408
- if (!existsSync10(metricsPath)) {
82424
+ if (!existsSync9(metricsPath)) {
82409
82425
  const latestPath = join8(phase0Path, "clusters/latest/metrics.json");
82410
- if (!existsSync10(latestPath)) {
82426
+ if (!existsSync9(latestPath)) {
82411
82427
  throw new Error(`Phase 0 metrics not found at ${metricsPath}`);
82412
82428
  }
82413
82429
  return JSON.parse(readFileSync8(latestPath, "utf-8"));
@@ -82528,17 +82544,17 @@ async function generateProductionClustering(options) {
82528
82544
  }
82529
82545
  function writeProductionArtifacts(result, outputPath) {
82530
82546
  const versionPath = join8(outputPath, result.version);
82531
- if (!existsSync10(versionPath)) {
82532
- mkdirSync4(versionPath, { recursive: true });
82547
+ if (!existsSync9(versionPath)) {
82548
+ mkdirSync3(versionPath, { recursive: true });
82533
82549
  }
82534
82550
  const resultPath = join8(versionPath, "clustering-result.json");
82535
- writeFileSync7(resultPath, JSON.stringify(result, null, 2));
82551
+ writeFileSync6(resultPath, JSON.stringify(result, null, 2));
82536
82552
  console.log(`\u2705 Written: ${resultPath}`);
82537
82553
  const assignmentsPath = join8(versionPath, "assignments.json");
82538
- writeFileSync7(assignmentsPath, JSON.stringify(result.assignments, null, 2));
82554
+ writeFileSync6(assignmentsPath, JSON.stringify(result.assignments, null, 2));
82539
82555
  console.log(`\u2705 Written: ${assignmentsPath}`);
82540
82556
  const clustersPath = join8(versionPath, "clusters.json");
82541
- writeFileSync7(
82557
+ writeFileSync6(
82542
82558
  clustersPath,
82543
82559
  JSON.stringify(
82544
82560
  {
@@ -82564,14 +82580,14 @@ function writeProductionArtifacts(result, outputPath) {
82564
82580
  priorityTier: c.priorityTier
82565
82581
  }))
82566
82582
  };
82567
- writeFileSync7(summaryPath, JSON.stringify(summary, null, 2));
82583
+ writeFileSync6(summaryPath, JSON.stringify(summary, null, 2));
82568
82584
  console.log(`\u2705 Written: ${summaryPath}`);
82569
82585
  const latestPath = join8(outputPath, "latest");
82570
- if (existsSync10(latestPath)) {
82586
+ if (existsSync9(latestPath)) {
82571
82587
  const { rmSync: rmSync2 } = __require("fs");
82572
82588
  rmSync2(latestPath, { recursive: true, force: true });
82573
82589
  }
82574
- mkdirSync4(latestPath, { recursive: true });
82590
+ mkdirSync3(latestPath, { recursive: true });
82575
82591
  for (const file of [
82576
82592
  "clustering-result.json",
82577
82593
  "assignments.json",
@@ -82580,7 +82596,7 @@ function writeProductionArtifacts(result, outputPath) {
82580
82596
  ]) {
82581
82597
  const src = join8(versionPath, file);
82582
82598
  const dst = join8(latestPath, file);
82583
- writeFileSync7(dst, readFileSync8(src));
82599
+ writeFileSync6(dst, readFileSync8(src));
82584
82600
  }
82585
82601
  console.log(`\u2705 Updated: ${latestPath}`);
82586
82602
  }
@@ -82638,19 +82654,19 @@ function validatePaths(phase0Path) {
82638
82654
  const assignmentsPath = join9(phase0Path, "clusters/v1/assignments.json");
82639
82655
  const labelsPath = join9(phase0Path, "clusters/v1/labels.json");
82640
82656
  const metricsPath = join9(phase0Path, "clusters/v1/metrics.json");
82641
- if (!existsSync11(assignmentsPath)) {
82657
+ if (!existsSync10(assignmentsPath)) {
82642
82658
  throw new CLIError({
82643
82659
  userMessage: `Phase 0 assignments not found at ${assignmentsPath}.`,
82644
82660
  suggestion: "Run Phase 0 clustering first or specify the correct --phase0-path."
82645
82661
  });
82646
82662
  }
82647
- if (!existsSync11(labelsPath)) {
82663
+ if (!existsSync10(labelsPath)) {
82648
82664
  throw new CLIError({
82649
82665
  userMessage: `Phase 0 labels not found at ${labelsPath}.`,
82650
82666
  suggestion: "Verify the --phase0-path points to valid artifacts."
82651
82667
  });
82652
82668
  }
82653
- if (!existsSync11(metricsPath)) {
82669
+ if (!existsSync10(metricsPath)) {
82654
82670
  throw new CLIError({
82655
82671
  userMessage: `Phase 0 metrics not found at ${metricsPath}.`,
82656
82672
  suggestion: "Verify the --phase0-path points to valid artifacts."
@@ -82731,12 +82747,12 @@ function registerFaqClusterCommands(program3) {
82731
82747
 
82732
82748
  // src/commands/faq/extract.ts
82733
82749
  init_esm_shims();
82734
- import { existsSync as existsSync13 } from "fs";
82750
+ import { existsSync as existsSync12 } from "fs";
82735
82751
  import { join as join11, resolve as resolve5 } from "path";
82736
82752
 
82737
82753
  // ../core/src/faq/extractor.ts
82738
82754
  init_esm_shims();
82739
- import { existsSync as existsSync12, mkdirSync as mkdirSync5, readFileSync as readFileSync9, writeFileSync as writeFileSync8 } from "fs";
82755
+ import { existsSync as existsSync11, mkdirSync as mkdirSync4, readFileSync as readFileSync9, writeFileSync as writeFileSync7 } from "fs";
82740
82756
  import { join as join10 } from "path";
82741
82757
 
82742
82758
  // ../core/src/faq/review.ts
@@ -83352,11 +83368,11 @@ async function extractFaqCandidates(options) {
83352
83368
  }
83353
83369
  function writeExtractionArtifacts(result, outputPath) {
83354
83370
  const versionPath = join10(outputPath, result.version);
83355
- if (!existsSync12(versionPath)) {
83356
- mkdirSync5(versionPath, { recursive: true });
83371
+ if (!existsSync11(versionPath)) {
83372
+ mkdirSync4(versionPath, { recursive: true });
83357
83373
  }
83358
83374
  const resultPath = join10(versionPath, "extraction-result.json");
83359
- writeFileSync8(resultPath, JSON.stringify(result, null, 2));
83375
+ writeFileSync7(resultPath, JSON.stringify(result, null, 2));
83360
83376
  console.log(`\u2705 Written: ${resultPath}`);
83361
83377
  const candidatesPath = join10(versionPath, "candidates.json");
83362
83378
  const candidatesData = {
@@ -83376,10 +83392,10 @@ function writeExtractionArtifacts(result, outputPath) {
83376
83392
  sourceConversations: c.sourceConversations.slice(0, 5)
83377
83393
  }))
83378
83394
  };
83379
- writeFileSync8(candidatesPath, JSON.stringify(candidatesData, null, 2));
83395
+ writeFileSync7(candidatesPath, JSON.stringify(candidatesData, null, 2));
83380
83396
  console.log(`\u2705 Written: ${candidatesPath}`);
83381
83397
  const statsPath = join10(versionPath, "stats.json");
83382
- writeFileSync8(
83398
+ writeFileSync7(
83383
83399
  statsPath,
83384
83400
  JSON.stringify(
83385
83401
  {
@@ -83393,11 +83409,11 @@ function writeExtractionArtifacts(result, outputPath) {
83393
83409
  );
83394
83410
  console.log(`\u2705 Written: ${statsPath}`);
83395
83411
  const latestPath = join10(outputPath, "latest");
83396
- if (existsSync12(latestPath)) {
83412
+ if (existsSync11(latestPath)) {
83397
83413
  const { rmSync: rmSync2 } = __require("fs");
83398
83414
  rmSync2(latestPath, { recursive: true, force: true });
83399
83415
  }
83400
- mkdirSync5(latestPath, { recursive: true });
83416
+ mkdirSync4(latestPath, { recursive: true });
83401
83417
  for (const file of [
83402
83418
  "extraction-result.json",
83403
83419
  "candidates.json",
@@ -83405,8 +83421,8 @@ function writeExtractionArtifacts(result, outputPath) {
83405
83421
  ]) {
83406
83422
  const src = join10(versionPath, file);
83407
83423
  const dst = join10(latestPath, file);
83408
- if (existsSync12(src)) {
83409
- writeFileSync8(dst, readFileSync9(src));
83424
+ if (existsSync11(src)) {
83425
+ writeFileSync7(dst, readFileSync9(src));
83410
83426
  }
83411
83427
  }
83412
83428
  console.log(`\u2705 Updated: ${latestPath}`);
@@ -83470,13 +83486,13 @@ var DEFAULT_GOLDEN_PATH = join11(
83470
83486
  var DEFAULT_OUTPUT_PATH3 = join11(PROJECT_ROOT3, "artifacts/phase-1/extraction");
83471
83487
  var DEFAULT_CACHE_PATH = `${process.env.HOME}/skill/data/front-cache.db`;
83472
83488
  function validatePaths2(ctx, clusteringPath, goldenPath, outputJson) {
83473
- if (!existsSync13(clusteringPath)) {
83489
+ if (!existsSync12(clusteringPath)) {
83474
83490
  throw new CLIError({
83475
83491
  userMessage: `Clustering result not found at ${clusteringPath}.`,
83476
83492
  suggestion: "Run `bun src/index.ts faq cluster` first to generate clustering."
83477
83493
  });
83478
83494
  }
83479
- if (goldenPath && !existsSync13(goldenPath)) {
83495
+ if (goldenPath && !existsSync12(goldenPath)) {
83480
83496
  if (!outputJson) {
83481
83497
  ctx.output.warn(`Golden responses not found at ${goldenPath}`);
83482
83498
  ctx.output.warn("Golden matching will be disabled.");
@@ -83505,7 +83521,7 @@ async function faqExtract(ctx, options) {
83505
83521
  ctx.output.data("");
83506
83522
  }
83507
83523
  validatePaths2(ctx, clusteringPath, goldenPath, outputJson);
83508
- if (!existsSync13(cachePath)) {
83524
+ if (!existsSync12(cachePath)) {
83509
83525
  const cliError = new CLIError({
83510
83526
  userMessage: `DuckDB cache not found at ${cachePath}.`,
83511
83527
  suggestion: "Run `bun src/index.ts front-cache sync` first to populate cache."
@@ -83527,7 +83543,7 @@ async function faqExtract(ctx, options) {
83527
83543
  }
83528
83544
  const extractionOptions = {
83529
83545
  clusteringPath,
83530
- goldenPath: existsSync13(goldenPath) ? goldenPath : void 0,
83546
+ goldenPath: existsSync12(goldenPath) ? goldenPath : void 0,
83531
83547
  source,
83532
83548
  outputPath,
83533
83549
  version,
@@ -83647,7 +83663,7 @@ function registerFaqExtractCommands(program3) {
83647
83663
 
83648
83664
  // src/commands/faq/mine.ts
83649
83665
  init_esm_shims();
83650
- import { writeFileSync as writeFileSync9 } from "fs";
83666
+ import { writeFileSync as writeFileSync8 } from "fs";
83651
83667
 
83652
83668
  // ../core/src/faq/index.ts
83653
83669
  init_esm_shims();
@@ -92464,7 +92480,7 @@ async function faqMine(ctx, options) {
92464
92480
  }))
92465
92481
  };
92466
92482
  if (options.export) {
92467
- writeFileSync9(options.export, JSON.stringify(rawData, null, 2), "utf-8");
92483
+ writeFileSync8(options.export, JSON.stringify(rawData, null, 2), "utf-8");
92468
92484
  if (outputJson) {
92469
92485
  ctx.output.data({
92470
92486
  success: true,
@@ -92538,7 +92554,7 @@ async function faqMine(ctx, options) {
92538
92554
  generatedAt: c.generatedAt.toISOString()
92539
92555
  }))
92540
92556
  };
92541
- writeFileSync9(
92557
+ writeFileSync8(
92542
92558
  options.export,
92543
92559
  JSON.stringify(exportData, null, 2),
92544
92560
  "utf-8"
@@ -92601,10 +92617,10 @@ function registerFaqMineCommands(program3) {
92601
92617
  // src/commands/faq/review.ts
92602
92618
  init_esm_shims();
92603
92619
  import { spawnSync } from "child_process";
92604
- import { existsSync as existsSync14, readFileSync as readFileSync10, unlinkSync, writeFileSync as writeFileSync10 } from "fs";
92620
+ import { existsSync as existsSync13, readFileSync as readFileSync10, unlinkSync, writeFileSync as writeFileSync9 } from "fs";
92605
92621
  import { tmpdir } from "os";
92606
92622
  import { join as join12 } from "path";
92607
- import { confirm as confirm2, select as select2 } from "@inquirer/prompts";
92623
+ import { confirm as confirm2, select as select3 } from "@inquirer/prompts";
92608
92624
  var COLORS2 = {
92609
92625
  reset: "\x1B[0m",
92610
92626
  green: "\x1B[32m",
@@ -92679,7 +92695,7 @@ Save and close the editor when done.
92679
92695
  The sections are separated by "## Question" and "## Answer" headers.
92680
92696
  -->
92681
92697
  `;
92682
- writeFileSync10(tmpFile, content, "utf-8");
92698
+ writeFileSync9(tmpFile, content, "utf-8");
92683
92699
  try {
92684
92700
  const result = spawnSync(editor, [tmpFile], {
92685
92701
  stdio: "inherit",
@@ -92707,7 +92723,7 @@ The sections are separated by "## Question" and "## Answer" headers.
92707
92723
  answer: editedAnswer
92708
92724
  };
92709
92725
  } finally {
92710
- if (existsSync14(tmpFile)) {
92726
+ if (existsSync13(tmpFile)) {
92711
92727
  unlinkSync(tmpFile);
92712
92728
  }
92713
92729
  }
@@ -92738,7 +92754,7 @@ ${COLORS2.bold}\u{1F4CB} FAQ Review Session${COLORS2.reset}`);
92738
92754
  for (let i = 0; i < candidates.length; i++) {
92739
92755
  const candidate = candidates[i];
92740
92756
  displayCandidate(ctx, candidate, i, candidates.length);
92741
- const action = await select2({
92757
+ const action = await select3({
92742
92758
  message: "Action:",
92743
92759
  choices: [
92744
92760
  {
@@ -94902,7 +94918,7 @@ function registerInboxCommand(front) {
94902
94918
 
94903
94919
  // src/commands/front/pull-conversations.ts
94904
94920
  init_esm_shims();
94905
- import { writeFileSync as writeFileSync11 } from "fs";
94921
+ import { writeFileSync as writeFileSync10 } from "fs";
94906
94922
  async function pullConversations(ctx, options) {
94907
94923
  const { inbox, limit: limit2 = 50, output, filter: filter4 } = options;
94908
94924
  const outputJson = options.json === true || ctx.format === "json";
@@ -95035,7 +95051,7 @@ Built ${samples.length} eval samples`);
95035
95051
  ctx.output.data(` ${cat}: ${count}`);
95036
95052
  }
95037
95053
  if (output) {
95038
- writeFileSync11(output, JSON.stringify(samples, null, 2));
95054
+ writeFileSync10(output, JSON.stringify(samples, null, 2));
95039
95055
  ctx.output.data(`
95040
95056
  Saved to ${output}`);
95041
95057
  } else if (outputJson) {
@@ -103216,7 +103232,7 @@ var compile3 = wrapCompile(compile2);
103216
103232
  var _compileUnsafe = wrapCompile(compileUnsafe);
103217
103233
  var _compileToken = wrapCompile(compileToken);
103218
103234
  function getSelectorFunc(searchFunc) {
103219
- return function select5(query, elements, options) {
103235
+ return function select7(query, elements, options) {
103220
103236
  const opts = convertOptionFormats(options);
103221
103237
  if (typeof query !== "function") {
103222
103238
  query = compileUnsafe(query, opts, elements);
@@ -103403,7 +103419,7 @@ function filterBySelector(selector, elements, options) {
103403
103419
  }
103404
103420
  return findFilterElements(elements, selector, options, false, elements.length);
103405
103421
  }
103406
- function select3(selector, root2, options = {}, limit2 = Infinity) {
103422
+ function select4(selector, root2, options = {}, limit2 = Infinity) {
103407
103423
  if (typeof selector === "function") {
103408
103424
  return find3(root2, selector);
103409
103425
  }
@@ -103508,7 +103524,7 @@ function _findBySelector(selector, limit2) {
103508
103524
  pseudos: this.options.pseudos,
103509
103525
  quirksMode: this.options.quirksMode
103510
103526
  };
103511
- return this._make(select3(selector, elems, options, limit2));
103527
+ return this._make(select4(selector, elems, options, limit2));
103512
103528
  }
103513
103529
  function _getMatcher(matchMap) {
103514
103530
  return function(fn, ...postFns) {
@@ -113870,6 +113886,216 @@ function registerKbCommands(program3) {
113870
113886
  });
113871
113887
  }
113872
113888
 
113889
+ // src/commands/keys/index.ts
113890
+ init_esm_shims();
113891
+ import { existsSync as existsSync14, readFileSync as readFileSync12 } from "fs";
113892
+ import { password as password2, select as select5 } from "@inquirer/prompts";
113893
+ import { Decrypter as Decrypter4 } from "age-encryption";
113894
+ var buildContext4 = async (command, json) => {
113895
+ const opts = typeof command.optsWithGlobals === "function" ? command.optsWithGlobals() : {
113896
+ ...command.parent?.opts(),
113897
+ ...command.opts()
113898
+ };
113899
+ return createContext({
113900
+ format: json ? "json" : opts.format,
113901
+ verbose: opts.verbose,
113902
+ quiet: opts.quiet
113903
+ });
113904
+ };
113905
+ async function getUserConfiguredKeys() {
113906
+ const keyPath = getAgeKeyPath();
113907
+ const configPath = getEncryptedConfigPath();
113908
+ if (!existsSync14(keyPath) || !existsSync14(configPath)) {
113909
+ return /* @__PURE__ */ new Set();
113910
+ }
113911
+ try {
113912
+ const identity = readFileSync12(keyPath, "utf8").trim();
113913
+ const encrypted = readFileSync12(configPath);
113914
+ const decrypter = new Decrypter4();
113915
+ decrypter.addIdentity(identity);
113916
+ const decrypted = await decrypter.decrypt(encrypted, "text");
113917
+ const keys = /* @__PURE__ */ new Set();
113918
+ for (const line of decrypted.split("\n")) {
113919
+ const trimmed = line.trim();
113920
+ if (!trimmed || trimmed.startsWith("#")) continue;
113921
+ const eqIndex = trimmed.indexOf("=");
113922
+ if (eqIndex > 0) {
113923
+ keys.add(trimmed.substring(0, eqIndex));
113924
+ }
113925
+ }
113926
+ return keys;
113927
+ } catch {
113928
+ return /* @__PURE__ */ new Set();
113929
+ }
113930
+ }
113931
+ async function showKeyStatus(ctx) {
113932
+ const userKeys = await getUserConfiguredKeys();
113933
+ const allKeys = Object.keys(SECRET_REFS);
113934
+ ctx.output.data("\n\u{1F4CB} API Key Status");
113935
+ ctx.output.data("\u2500".repeat(60));
113936
+ const personal = [];
113937
+ const shared = [];
113938
+ const notSet = [];
113939
+ for (const key of allKeys) {
113940
+ const provenance = getKeyProvenance(key);
113941
+ const hasUserKey = userKeys.has(key);
113942
+ const hasEnvValue = !!process.env[key];
113943
+ if (hasUserKey) {
113944
+ personal.push(key);
113945
+ } else if (provenance === "shipped" || hasEnvValue) {
113946
+ shared.push(key);
113947
+ } else {
113948
+ notSet.push(key);
113949
+ }
113950
+ }
113951
+ if (personal.length > 0) {
113952
+ ctx.output.data("\n\u{1F510} Your personal keys:");
113953
+ for (const key of personal) {
113954
+ ctx.output.data(` \u2713 ${key}`);
113955
+ }
113956
+ }
113957
+ if (shared.length > 0) {
113958
+ ctx.output.data("\n\u{1F3E2} Using shared/shipped keys:");
113959
+ for (const key of shared.slice(0, 5)) {
113960
+ ctx.output.data(` \u2022 ${key}`);
113961
+ }
113962
+ if (shared.length > 5) {
113963
+ ctx.output.data(` \u2022 ... and ${shared.length - 5} more`);
113964
+ }
113965
+ }
113966
+ if (notSet.length > 0 && notSet.length < 10) {
113967
+ ctx.output.data("\n\u26A0\uFE0F Not configured:");
113968
+ for (const key of notSet) {
113969
+ ctx.output.data(` \u25CB ${key}`);
113970
+ }
113971
+ }
113972
+ ctx.output.data("");
113973
+ }
113974
+ async function interactiveKeySetup(ctx) {
113975
+ const keyPath = getAgeKeyPath();
113976
+ if (!existsSync14(keyPath)) {
113977
+ ctx.output.data("\n\u{1F511} First time setup - creating your encryption key...\n");
113978
+ await configInitAction(ctx, { json: false });
113979
+ ctx.output.data("");
113980
+ }
113981
+ await showKeyStatus(ctx);
113982
+ ctx.output.data("\u2500".repeat(60));
113983
+ ctx.output.data("");
113984
+ try {
113985
+ const action = await select5({
113986
+ message: "What would you like to do?",
113987
+ choices: [
113988
+ { name: "Add/update a personal API key", value: "add" },
113989
+ { name: "View all available keys", value: "list" },
113990
+ { name: "Exit", value: "exit" }
113991
+ ]
113992
+ });
113993
+ if (action === "exit") {
113994
+ return;
113995
+ }
113996
+ if (action === "list") {
113997
+ ctx.output.data("\n\u{1F4CB} Available API keys you can personalize:\n");
113998
+ const keys = Object.keys(SECRET_REFS);
113999
+ for (const key of keys) {
114000
+ ctx.output.data(` \u2022 ${key}`);
114001
+ }
114002
+ ctx.output.data("\nRun `skill keys add` to set one.");
114003
+ return;
114004
+ }
114005
+ if (action === "add") {
114006
+ const selectedKey = await select5({
114007
+ message: "Which key do you want to set?",
114008
+ choices: Object.keys(SECRET_REFS).map((key) => ({
114009
+ name: key,
114010
+ value: key
114011
+ }))
114012
+ });
114013
+ const value = await password2({
114014
+ message: `Enter your ${selectedKey}:`
114015
+ });
114016
+ if (!value) {
114017
+ ctx.output.data("Cancelled - no value provided.");
114018
+ return;
114019
+ }
114020
+ await configSetAction(ctx, `${selectedKey}=${value}`, { json: false });
114021
+ }
114022
+ } catch (error) {
114023
+ if (error instanceof Error && (error.message.includes("User force closed") || error.message.includes("canceled"))) {
114024
+ ctx.output.data("\nCancelled.");
114025
+ return;
114026
+ }
114027
+ throw error;
114028
+ }
114029
+ }
114030
+ function registerKeysCommands(program3) {
114031
+ const keys = program3.command("keys").description(
114032
+ "Manage your personal API keys\n\n Use your own API keys instead of shared defaults.\n Keys are encrypted and stored in ~/.config/skill/\n\n Examples:\n skill keys Interactive setup\n skill keys status Show which keys are personal vs shared\n skill keys add Add a personal API key"
114033
+ ).action(async (_options, command) => {
114034
+ const ctx = await buildContext4(command, false);
114035
+ if (!process.stdin.isTTY) {
114036
+ ctx.output.error(
114037
+ "Interactive mode requires a TTY. Use `skill keys add KEY=value` for scripting."
114038
+ );
114039
+ return;
114040
+ }
114041
+ await interactiveKeySetup(ctx);
114042
+ });
114043
+ keys.command("status").description("Show which API keys are personal vs shared").option("--json", "Output as JSON").action(async (options, command) => {
114044
+ const ctx = await buildContext4(command, options.json);
114045
+ if (options.json || ctx.format === "json") {
114046
+ const userKeys = await getUserConfiguredKeys();
114047
+ const allKeys = Object.keys(SECRET_REFS);
114048
+ const status = {};
114049
+ for (const key of allKeys) {
114050
+ const provenance = getKeyProvenance(key);
114051
+ if (userKeys.has(key)) {
114052
+ status[key] = "personal";
114053
+ } else if (provenance === "shipped" || process.env[key]) {
114054
+ status[key] = "shared";
114055
+ } else {
114056
+ status[key] = "not_set";
114057
+ }
114058
+ }
114059
+ ctx.output.data({ keys: status });
114060
+ } else {
114061
+ await showKeyStatus(ctx);
114062
+ }
114063
+ });
114064
+ keys.command("add [key-value]").description(
114065
+ "Add a personal API key\n\n Interactive: skill keys add\n Direct: skill keys add LINEAR_API_KEY=lin_xxx"
114066
+ ).option("--json", "Output as JSON").action(async (keyValue, options, command) => {
114067
+ const ctx = await buildContext4(command, options.json);
114068
+ const keyPath = getAgeKeyPath();
114069
+ if (!existsSync14(keyPath)) {
114070
+ if (process.stdin.isTTY && !options.json) {
114071
+ ctx.output.data(
114072
+ "\u{1F511} First time setup - creating your encryption key...\n"
114073
+ );
114074
+ }
114075
+ await configInitAction(ctx, { json: options.json });
114076
+ }
114077
+ await configSetAction(ctx, keyValue, options);
114078
+ });
114079
+ keys.command("list").description("List your personal API keys (names only, values hidden)").option("--show-values", "Show decrypted values").option("--json", "Output as JSON").action(async (options, command) => {
114080
+ const ctx = await buildContext4(command, options.json);
114081
+ const userKeys = await getUserConfiguredKeys();
114082
+ if (options.json || ctx.format === "json") {
114083
+ ctx.output.data({ personalKeys: Array.from(userKeys) });
114084
+ } else {
114085
+ if (userKeys.size === 0) {
114086
+ ctx.output.data("No personal keys configured.");
114087
+ ctx.output.data("\nRun `skill keys add` to set one.");
114088
+ } else {
114089
+ ctx.output.data("\n\u{1F510} Your personal API keys:\n");
114090
+ for (const key of userKeys) {
114091
+ ctx.output.data(` \u2022 ${key}`);
114092
+ }
114093
+ ctx.output.data("");
114094
+ }
114095
+ }
114096
+ });
114097
+ }
114098
+
113873
114099
  // src/commands/linear/index.ts
113874
114100
  init_esm_shims();
113875
114101
 
@@ -113886,7 +114112,7 @@ function requirePersonalKey(keyName) {
113886
114112
  throw new CLIError({
113887
114113
  userMessage: `Write operations require a personal API key for ${keyName}.`,
113888
114114
  exitCode: EXIT_CODES.auth,
113889
- suggestion: "Run 'skill config init' to set up your personal keys.",
114115
+ suggestion: "Run 'skill keys add' to set up your personal keys.",
113890
114116
  debugMessage: `Key provenance for ${keyName}: ${provenance ?? "undefined"}`
113891
114117
  });
113892
114118
  }
@@ -113922,8 +114148,8 @@ function hateoasWrap2(opts) {
113922
114148
  return response;
113923
114149
  }
113924
114150
  var WRITE_ACTION_META = {
113925
- personal_key_hint: "\u26A0\uFE0F Write operations require a personal LINEAR_API_KEY. Run `skill config init` to set up your keys.",
113926
- setup_command: "skill config init"
114151
+ personal_key_hint: "\u26A0\uFE0F Write operations require a personal LINEAR_API_KEY. Run `skill keys add` to set up your keys.",
114152
+ setup_command: "skill keys add"
113927
114153
  };
113928
114154
  function issueLinks(identifier, teamKey) {
113929
114155
  const links = [
@@ -114784,7 +115010,7 @@ async function getIssue(ctx, id) {
114784
115010
  ctx.output.data(` \u2022 Close: skill linear close ${issue.identifier}`);
114785
115011
  ctx.output.data("");
114786
115012
  ctx.output.data(" \u26A0\uFE0F Write operations require a personal LINEAR_API_KEY.");
114787
- ctx.output.data(" Run `skill config init` to set up your keys.");
115013
+ ctx.output.data(" Run `skill keys add` to set up your keys.");
114788
115014
  ctx.output.data("");
114789
115015
  } catch (error) {
114790
115016
  const cliError = error instanceof CLIError ? error : new CLIError({
@@ -116713,7 +116939,7 @@ async function deleteMemory(ctx, id, options) {
116713
116939
  }
116714
116940
 
116715
116941
  // src/commands/memory/index.ts
116716
- var buildContext4 = async (command, json) => {
116942
+ var buildContext5 = async (command, json) => {
116717
116943
  const opts = typeof command.optsWithGlobals === "function" ? command.optsWithGlobals() : {
116718
116944
  ...command.parent?.opts(),
116719
116945
  ...command.opts()
@@ -116727,42 +116953,42 @@ var buildContext4 = async (command, json) => {
116727
116953
  function registerMemoryCommands(program3) {
116728
116954
  const memory = program3.command("memory").description("Manage semantic memory for agent learning");
116729
116955
  memory.command("store").description("Store a new memory").argument("<content>", "Memory content to store").option("--tags <tags>", "Comma-separated tags").option("--collection <collection>", "Collection name (default: learnings)").option("--app <app>", "App slug to associate with memory").option("--json", "Output as JSON").action(async (content, options, command) => {
116730
- const ctx = await buildContext4(command, options.json);
116956
+ const ctx = await buildContext5(command, options.json);
116731
116957
  await store(ctx, content, options);
116732
116958
  });
116733
116959
  memory.command("find").description("Search memories by semantic similarity").argument("<query>", "Search query text").option("--limit <number>", "Max results (1-100, default: 10)").option("--collection <collection>", "Collection name (default: learnings)").option("--app <app>", "Filter by app slug").option(
116734
116960
  "--min-confidence <confidence>",
116735
116961
  "Minimum confidence threshold (0-1, default: 0.5)"
116736
116962
  ).option("--json", "Output as JSON").action(async (query, options, command) => {
116737
- const ctx = await buildContext4(command, options.json);
116963
+ const ctx = await buildContext5(command, options.json);
116738
116964
  await find5(ctx, query, options);
116739
116965
  });
116740
116966
  memory.command("get").description("Get a specific memory by ID").argument("<id>", "Memory ID").option("--collection <collection>", "Collection name (default: learnings)").option("--json", "Output as JSON").action(async (id, options, command) => {
116741
- const ctx = await buildContext4(command, options.json);
116967
+ const ctx = await buildContext5(command, options.json);
116742
116968
  await get2(ctx, id, options);
116743
116969
  });
116744
116970
  memory.command("validate").description("Validate a memory (resets decay clock)").argument("<id>", "Memory ID").option("--collection <collection>", "Collection name (default: learnings)").option("--json", "Output as JSON").action(async (id, options, command) => {
116745
- const ctx = await buildContext4(command, options.json);
116971
+ const ctx = await buildContext5(command, options.json);
116746
116972
  await validate2(ctx, id, options);
116747
116973
  });
116748
116974
  memory.command("upvote").description("Upvote a memory").argument("<id>", "Memory ID").option("--collection <collection>", "Collection name (default: learnings)").option("--reason <reason>", "Optional reason for upvote").option("--json", "Output as JSON").action(async (id, options, command) => {
116749
- const ctx = await buildContext4(command, options.json);
116975
+ const ctx = await buildContext5(command, options.json);
116750
116976
  await upvote(ctx, id, options);
116751
116977
  });
116752
116978
  memory.command("downvote").description("Downvote a memory").argument("<id>", "Memory ID").option("--collection <collection>", "Collection name (default: learnings)").option("--reason <reason>", "Optional reason for downvote").option("--json", "Output as JSON").action(async (id, options, command) => {
116753
- const ctx = await buildContext4(command, options.json);
116979
+ const ctx = await buildContext5(command, options.json);
116754
116980
  await downvote(ctx, id, options);
116755
116981
  });
116756
116982
  memory.command("delete").description("Delete a memory").argument("<id>", "Memory ID").option("--collection <collection>", "Collection name (default: learnings)").option("--json", "Output as JSON").action(async (id, options, command) => {
116757
- const ctx = await buildContext4(command, options.json);
116983
+ const ctx = await buildContext5(command, options.json);
116758
116984
  await deleteMemory(ctx, id, options);
116759
116985
  });
116760
116986
  memory.command("stats").description("Display memory statistics").option("--collection <collection>", "Filter by collection").option("--app <app>", "Filter by app slug").option("--json", "Output as JSON").action(async (options, command) => {
116761
- const ctx = await buildContext4(command, options.json);
116987
+ const ctx = await buildContext5(command, options.json);
116762
116988
  await stats3(ctx, options);
116763
116989
  });
116764
116990
  memory.command("stale").description("List stale memories needing validation").option("--collection <collection>", "Filter by collection").option("--threshold <threshold>", "Confidence threshold (default: 0.25)").option("--json", "Output as JSON").action(async (options, command) => {
116765
- const ctx = await buildContext4(command, options.json);
116991
+ const ctx = await buildContext5(command, options.json);
116766
116992
  await stale(ctx, options);
116767
116993
  });
116768
116994
  }
@@ -117344,7 +117570,7 @@ async function buildValidateDatasetFromProduction(productionResultsPath, outputP
117344
117570
  }
117345
117571
 
117346
117572
  // src/commands/pipeline.ts
117347
- var buildContext5 = async (command, json) => {
117573
+ var buildContext6 = async (command, json) => {
117348
117574
  const opts = typeof command.optsWithGlobals === "function" ? command.optsWithGlobals() : {
117349
117575
  ...command.parent?.opts(),
117350
117576
  ...command.opts()
@@ -117415,7 +117641,7 @@ function registerPipelineCommands(program3) {
117415
117641
  "Model for LLM classification",
117416
117642
  "anthropic/claude-haiku-4-5"
117417
117643
  ).action(async (opts, command) => {
117418
- const ctx = await buildContext5(command, opts.json);
117644
+ const ctx = await buildContext6(command, opts.json);
117419
117645
  try {
117420
117646
  await runClassifyEval2({
117421
117647
  ...opts,
@@ -117426,7 +117652,7 @@ function registerPipelineCommands(program3) {
117426
117652
  }
117427
117653
  });
117428
117654
  pipeline.command("build-classify-dataset").description("Build classify eval dataset from production data").requiredOption("--production <file>", "Production dataset JSON").requiredOption("--output <file>", "Output scenarios JSON").action(async (opts, command) => {
117429
- const ctx = await buildContext5(command);
117655
+ const ctx = await buildContext6(command);
117430
117656
  try {
117431
117657
  await buildClassifyDataset(opts.production, opts.output);
117432
117658
  ctx.output.success(`Dataset written to ${opts.output}`);
@@ -117438,7 +117664,7 @@ function registerPipelineCommands(program3) {
117438
117664
  "--dataset <file>",
117439
117665
  "Path to scenarios JSON (uses built-in if not provided)"
117440
117666
  ).option("--output <file>", "Save results to JSON").option("--verbose", "Show individual failures").option("--json", "JSON output").action(async (opts, command) => {
117441
- const ctx = await buildContext5(command, opts.json);
117667
+ const ctx = await buildContext6(command, opts.json);
117442
117668
  try {
117443
117669
  await runValidateEval2({
117444
117670
  ...opts,
@@ -117449,7 +117675,7 @@ function registerPipelineCommands(program3) {
117449
117675
  }
117450
117676
  });
117451
117677
  pipeline.command("build-validate-dataset").description("Build validate eval dataset from production failures").requiredOption("--production <file>", "Production baseline results JSON").requiredOption("--output <file>", "Output scenarios JSON").action(async (opts, command) => {
117452
- const ctx = await buildContext5(command);
117678
+ const ctx = await buildContext6(command);
117453
117679
  try {
117454
117680
  await buildValidateDatasetFromProduction(opts.production, opts.output);
117455
117681
  ctx.output.success(`Dataset written to ${opts.output}`);
@@ -117462,7 +117688,7 @@ function registerPipelineCommands(program3) {
117462
117688
  "Model for LLM steps",
117463
117689
  "anthropic/claude-haiku-4-5"
117464
117690
  ).action(async (opts, command) => {
117465
- const ctx = await buildContext5(command, opts.json);
117691
+ const ctx = await buildContext6(command, opts.json);
117466
117692
  try {
117467
117693
  await runE2EEval2({ ...opts, json: opts.json ?? ctx.format === "json" });
117468
117694
  } catch (error) {
@@ -117470,7 +117696,7 @@ function registerPipelineCommands(program3) {
117470
117696
  }
117471
117697
  });
117472
117698
  pipeline.command("run").description("Run pipeline on a single message").requiredOption("--subject <text>", "Message subject").requiredOption("--body <text>", "Message body").option("--app <id>", "App ID", "total-typescript").option("--dry-run", "Don't actually send", true).option("--json", "JSON output").action(async (opts, command) => {
117473
- const ctx = await buildContext5(command, opts.json);
117699
+ const ctx = await buildContext6(command, opts.json);
117474
117700
  await runPipelineCommand(ctx, opts);
117475
117701
  });
117476
117702
  }
@@ -117478,10 +117704,10 @@ function registerPipelineCommands(program3) {
117478
117704
  // src/commands/plugin-sync.ts
117479
117705
  init_esm_shims();
117480
117706
  import { homedir as homedir3 } from "os";
117481
- import { dirname as dirname4, join as join13, resolve as resolve6 } from "path";
117707
+ import { dirname as dirname3, join as join13, resolve as resolve6 } from "path";
117482
117708
  import { fileURLToPath } from "url";
117483
117709
  var PLUGIN_SOURCE_DIR = resolve6(
117484
- dirname4(fileURLToPath(import.meta.url)),
117710
+ dirname3(fileURLToPath(import.meta.url)),
117485
117711
  "../../plugin"
117486
117712
  );
117487
117713
  var PLUGIN_MANIFEST_RELATIVE = join13(".claude-plugin", "plugin.json");
@@ -117587,7 +117813,7 @@ var registerPluginSyncCommand = (program3) => {
117587
117813
 
117588
117814
  // src/commands/responses.ts
117589
117815
  init_esm_shims();
117590
- import { writeFileSync as writeFileSync12 } from "fs";
117816
+ import { writeFileSync as writeFileSync11 } from "fs";
117591
117817
  function formatDate3(date) {
117592
117818
  return date.toLocaleString("en-US", {
117593
117819
  month: "short",
@@ -118120,7 +118346,7 @@ async function exportResponses(ctx, options) {
118120
118346
  }
118121
118347
  const outputJson = JSON.stringify(exportData, null, 2);
118122
118348
  if (options.output) {
118123
- writeFileSync12(options.output, outputJson, "utf-8");
118349
+ writeFileSync11(options.output, outputJson, "utf-8");
118124
118350
  if (!outputJsonFormat) {
118125
118351
  ctx.output.success(
118126
118352
  `Exported ${exportData.length} responses to ${options.output}`
@@ -118769,7 +118995,7 @@ init_esm_shims();
118769
118995
  import { spawn } from "child_process";
118770
118996
  import { writeFile as writeFile7 } from "fs/promises";
118771
118997
  import { homedir as homedir4 } from "os";
118772
- import { dirname as dirname5, join as join14 } from "path";
118998
+ import { dirname as dirname4, join as join14 } from "path";
118773
118999
  var CONFIG_DIR_NAME = "skill-cli";
118774
119000
  var AUTO_UPDATE_STATE_FILE = "auto-update.json";
118775
119001
  var DEFAULT_PACKAGE = "@skillrecordings/cli";
@@ -118799,7 +119025,7 @@ var AutoUpdateStore = class {
118799
119025
  }
118800
119026
  async save(state) {
118801
119027
  try {
118802
- await ensureDir(dirname5(this.filePath));
119028
+ await ensureDir(dirname4(this.filePath));
118803
119029
  await writeFile7(this.filePath, JSON.stringify(state, null, 2), "utf-8");
118804
119030
  } catch {
118805
119031
  }
@@ -119005,7 +119231,7 @@ var DEFAULT_HINT_RULES = [
119005
119231
  {
119006
119232
  id: "onboarding.auth",
119007
119233
  audience: "onboarding",
119008
- message: "Configure credentials with `skill init` to unlock the full CLI.",
119234
+ message: "Set up your own API keys with `skill keys`.",
119009
119235
  showWhen: (state) => state.totalRuns >= 1 && !hasMilestone(state, "auth_configured"),
119010
119236
  retireWhen: (state) => hasMilestone(state, "auth_configured")
119011
119237
  },
@@ -119037,6 +119263,13 @@ var DEFAULT_HINT_RULES = [
119037
119263
  showWhen: (state) => state.totalRuns >= 3 && !hasCommandPrefix(state, "axiom."),
119038
119264
  retireWhen: (state) => hasCommandPrefix(state, "axiom.")
119039
119265
  },
119266
+ {
119267
+ id: "discovery.keys",
119268
+ audience: "discovery",
119269
+ message: "Override shared credentials with your own: `skill keys add`",
119270
+ showWhen: (state) => state.totalRuns >= 3 && !hasCommand(state, "keys") && !hasMilestone(state, "auth_configured"),
119271
+ retireWhen: (state) => hasCommand(state, "keys") || hasCommand(state, "keys.add") || hasMilestone(state, "auth_configured")
119272
+ },
119040
119273
  {
119041
119274
  id: "context.front.triage",
119042
119275
  audience: "contextual",
@@ -119107,10 +119340,10 @@ var writeHints = (hints, stderr) => {
119107
119340
  init_esm_shims();
119108
119341
  import { lstat, readlink, symlink } from "fs/promises";
119109
119342
  import { homedir as homedir5 } from "os";
119110
- import { dirname as dirname6, join as join15, resolve as resolve7 } from "path";
119343
+ import { dirname as dirname5, join as join15, resolve as resolve7 } from "path";
119111
119344
  import { fileURLToPath as fileURLToPath2 } from "url";
119112
119345
  var SKILL_SOURCE_DIR = resolve7(
119113
- dirname6(fileURLToPath2(import.meta.url)),
119346
+ dirname5(fileURLToPath2(import.meta.url)),
119114
119347
  "../../../../.claude/skills/skill-cli"
119115
119348
  );
119116
119349
  var SKILL_TARGET_DIR = join15(homedir5(), ".claude", "skills", "skill-cli");
@@ -119124,7 +119357,7 @@ async function autoLinkSkill() {
119124
119357
  } catch (e) {
119125
119358
  if (e.code === "ENOENT") {
119126
119359
  const { mkdir: mkdir2 } = await import("fs/promises");
119127
- await mkdir2(dirname6(target), { recursive: true });
119360
+ await mkdir2(dirname5(target), { recursive: true });
119128
119361
  await symlink(source, target, "dir");
119129
119362
  return {
119130
119363
  status: "linked",
@@ -119137,7 +119370,7 @@ async function autoLinkSkill() {
119137
119370
  }
119138
119371
  if (stats4.isSymbolicLink()) {
119139
119372
  const linkTarget = await readlink(target);
119140
- const resolvedLinkTarget = resolve7(dirname6(target), linkTarget);
119373
+ const resolvedLinkTarget = resolve7(dirname5(target), linkTarget);
119141
119374
  if (resolvedLinkTarget === source || linkTarget === source) {
119142
119375
  return {
119143
119376
  status: "exists",
@@ -119217,7 +119450,7 @@ async function sendTelemetryEvent(event) {
119217
119450
  init_esm_shims();
119218
119451
  import { writeFile as writeFile8 } from "fs/promises";
119219
119452
  import { homedir as homedir6 } from "os";
119220
- import { dirname as dirname7, join as join16 } from "path";
119453
+ import { dirname as dirname6, join as join16 } from "path";
119221
119454
  var CONFIG_DIR_NAME2 = "skill-cli";
119222
119455
  var USAGE_FILE_NAME = "usage.json";
119223
119456
  function resolveConfigDir2(configDir) {
@@ -119287,7 +119520,7 @@ var UsageTracker = class {
119287
119520
  }
119288
119521
  async saveState(state) {
119289
119522
  try {
119290
- await ensureDir(dirname7(this.filePath));
119523
+ await ensureDir(dirname6(this.filePath));
119291
119524
  await writeFile8(this.filePath, JSON.stringify(state, null, 2), "utf-8");
119292
119525
  } catch {
119293
119526
  }
@@ -119843,8 +120076,8 @@ if (!envLoaded && !process.env.DATABASE_URL) {
119843
120076
  process.env.SKIP_ENV_VALIDATION = "1";
119844
120077
  }
119845
120078
  var runtimeTarget = `bun-${process.platform}-${process.arch}`;
119846
- var buildVersion = "0.14.3".length > 0 ? "0.14.3" : "0.0.0-dev";
119847
- var buildCommit = "ba0a512".length > 0 ? "ba0a512" : "dev";
120079
+ var buildVersion = "0.16.0".length > 0 ? "0.16.0" : "0.0.0-dev";
120080
+ var buildCommit = "d96a5e3".length > 0 ? "d96a5e3" : "dev";
119848
120081
  var buildTarget = "node".length > 0 ? "node" : runtimeTarget;
119849
120082
  var isDevBuild = buildVersion.includes("dev") || buildCommit === "dev";
119850
120083
  var versionLabel = `skill v${buildVersion} (${buildCommit}) ${buildTarget}`;
@@ -119889,7 +120122,7 @@ var resolveMilestones = (commandName) => {
119889
120122
  case "wizard":
119890
120123
  return ["wizard_completed"];
119891
120124
  case "auth.setup":
119892
- case "init":
120125
+ case "config.init":
119893
120126
  return ["auth_configured"];
119894
120127
  default:
119895
120128
  return [];
@@ -120063,6 +120296,7 @@ registerDeployCommands(program2);
120063
120296
  registerKbCommands(program2);
120064
120297
  registerAuthCommands(program2, usageState);
120065
120298
  registerConfigCommands(program2);
120299
+ registerKeysCommands(program2);
120066
120300
  registerPluginSyncCommand(program2);
120067
120301
  program2.command("mcp").description(
120068
120302
  "Start MCP server for AI coding agent integration.\n Exposes 9 Front tools over JSON-RPC stdio for Claude Code, Cursor, etc.\n Tools: inbox, conversation, message, assign, reply, tag, archive, search, report\n Usage: skill mcp (then connect your AI editor to stdin/stdout)"