@skillrecordings/cli 0.15.0 → 0.16.1
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 +423 -203
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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,
|
|
1482
|
+
module.exports.setThePassword = function(url, password3) {
|
|
1483
1483
|
url.password = "";
|
|
1484
|
-
const decoded = punycode.ucs2.decode(
|
|
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:
|
|
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 &&
|
|
16752
|
-
this[kProxyHeaders]["proxy-authorization"] = `Basic ${Buffer.from(`${decodeURIComponent(username)}:${decodeURIComponent(
|
|
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:
|
|
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(
|
|
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:
|
|
26410
|
-
authorizationValue = `Basic ${Buffer.from(`${username}:${
|
|
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,24 +74714,24 @@ 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
|
|
74718
|
-
abbreviated: "Skill Recordings support agent CLI \u2014 triage and investigate support conversations.\n\n Start here:\n skill
|
|
74719
|
-
minimal: "Skill Recordings support agent CLI. Try: skill
|
|
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
|
-
full: "Front conversations, inboxes, tags, archival, and reporting.\n\n
|
|
74723
|
-
abbreviated: "Front API workflows for inbox triage and conversation actions.\n\n Common:\n skill front inbox\n skill front triage\n skill front conversation <id> -m\n skill front reply <id>\n skill front archive <id
|
|
74724
|
-
minimal: "Front API commands (inbox, triage, assign, reply, archive).
|
|
74722
|
+
full: "Front conversations, inboxes, tags, archival, and reporting.\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.",
|
|
74723
|
+
abbreviated: "Front API workflows for inbox triage and conversation actions.\n\n Common:\n skill front inbox\n skill front triage\n skill front conversation <id> -m\n skill front reply <id>\n skill front archive <id>",
|
|
74724
|
+
minimal: "Front API commands (inbox, triage, assign, reply, archive)."
|
|
74725
74725
|
};
|
|
74726
74726
|
var AUTH_DESCRIPTIONS = {
|
|
74727
|
-
full: "
|
|
74728
|
-
abbreviated: "
|
|
74729
|
-
minimal: "Auth
|
|
74727
|
+
full: "View CLI authentication status.\n\n Check your setup:\n skill auth status Shows which secrets are loaded\n skill auth whoami Verify your 1Password service account identity\n\n API keys ship with the CLI (encrypted). To override with personal keys:\n skill keys Manage personal API key overrides",
|
|
74728
|
+
abbreviated: "View CLI authentication status.\n\n Commands:\n skill auth status\n skill auth whoami",
|
|
74729
|
+
minimal: "Auth status commands (auth status, auth whoami)."
|
|
74730
74730
|
};
|
|
74731
74731
|
var INNGEST_DESCRIPTIONS = {
|
|
74732
|
-
full: "Inngest event and workflow commands.\n\n Debug pipeline runs:\n skill inngest runs --status failed --after 1h Recent failures\n skill inngest events --after 12h Recent events\n skill inngest investigate <run-id> Deep-dive a specific run
|
|
74733
|
-
abbreviated: "Inngest events and workflow runs.\n\n Common:\n skill inngest runs --status failed --after 1h\n skill inngest events --after 12h\n skill inngest investigate <run-id
|
|
74734
|
-
minimal: "Inngest events and runs debugging.
|
|
74732
|
+
full: "Inngest event and workflow commands.\n\n Debug pipeline runs:\n skill inngest runs --status failed --after 1h Recent failures\n skill inngest events --after 12h Recent events\n skill inngest investigate <run-id> Deep-dive a specific run",
|
|
74733
|
+
abbreviated: "Inngest events and workflow runs.\n\n Common:\n skill inngest runs --status failed --after 1h\n skill inngest events --after 12h\n skill inngest investigate <run-id>",
|
|
74734
|
+
minimal: "Inngest events and runs debugging."
|
|
74735
74735
|
};
|
|
74736
74736
|
var GROUP_DESCRIPTIONS = {
|
|
74737
74737
|
root: ROOT_DESCRIPTIONS,
|
|
@@ -76954,11 +76954,11 @@ Saved to ${options.output}`);
|
|
|
76954
76954
|
}
|
|
76955
76955
|
}
|
|
76956
76956
|
async function toEvalite(options) {
|
|
76957
|
-
const { readFileSync:
|
|
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
|
-
|
|
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
|
|
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,68 +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
|
|
77040
|
-
|
|
77041
|
-
|
|
77042
|
-
|
|
77043
|
-
|
|
77044
|
-
|
|
77045
|
-
|
|
77046
|
-
|
|
77047
|
-
|
|
77048
|
-
|
|
77049
|
-
|
|
77050
|
-
|
|
77051
|
-
To
|
|
77052
|
-
|
|
77053
|
-
|
|
77054
|
-
|
|
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 { password, select as select2 } from "@inquirer/prompts";
|
|
77100
|
-
import { Decrypter, Encrypter, identityToRecipient as identityToRecipient2 } from "age-encryption";
|
|
77101
77064
|
function getEncryptedConfigPath() {
|
|
77102
77065
|
return `${getUserConfigDir2()}/.env.user.encrypted`;
|
|
77103
77066
|
}
|
|
@@ -77110,7 +77073,7 @@ function parseKeyValue(input2) {
|
|
|
77110
77073
|
return { key, value };
|
|
77111
77074
|
}
|
|
77112
77075
|
async function readExistingConfig(identity, configPath) {
|
|
77113
|
-
if (!
|
|
77076
|
+
if (!existsSync3(configPath)) {
|
|
77114
77077
|
return {};
|
|
77115
77078
|
}
|
|
77116
77079
|
try {
|
|
@@ -77137,7 +77100,7 @@ async function readExistingConfig(identity, configPath) {
|
|
|
77137
77100
|
async function configSetAction(ctx, keyValue, options = {}) {
|
|
77138
77101
|
const outputJson = options.json === true || ctx.format === "json";
|
|
77139
77102
|
const keyPath = getAgeKeyPath();
|
|
77140
|
-
if (!
|
|
77103
|
+
if (!existsSync3(keyPath)) {
|
|
77141
77104
|
const result = {
|
|
77142
77105
|
success: false,
|
|
77143
77106
|
error: "Age key not found. Run: skill config init"
|
|
@@ -77189,7 +77152,7 @@ async function configSetAction(ctx, keyValue, options = {}) {
|
|
|
77189
77152
|
}
|
|
77190
77153
|
try {
|
|
77191
77154
|
const identity = readFileSync2(keyPath, "utf8").trim();
|
|
77192
|
-
const recipient = await
|
|
77155
|
+
const recipient = await identityToRecipient(identity);
|
|
77193
77156
|
const configPath = getEncryptedConfigPath();
|
|
77194
77157
|
const config = await readExistingConfig(identity, configPath);
|
|
77195
77158
|
config[parsed.key] = parsed.value;
|
|
@@ -77197,7 +77160,7 @@ async function configSetAction(ctx, keyValue, options = {}) {
|
|
|
77197
77160
|
const encrypter = new Encrypter();
|
|
77198
77161
|
encrypter.addRecipient(recipient);
|
|
77199
77162
|
const encrypted = await encrypter.encrypt(envContent + "\n");
|
|
77200
|
-
|
|
77163
|
+
writeFileSync3(configPath, Buffer.from(encrypted));
|
|
77201
77164
|
const result = {
|
|
77202
77165
|
success: true,
|
|
77203
77166
|
key: parsed.key,
|
|
@@ -77224,9 +77187,24 @@ async function configSetAction(ctx, keyValue, options = {}) {
|
|
|
77224
77187
|
}
|
|
77225
77188
|
|
|
77226
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
|
+
}
|
|
77227
77205
|
async function decryptConfig(identity) {
|
|
77228
77206
|
const configPath = getEncryptedConfigPath();
|
|
77229
|
-
if (!
|
|
77207
|
+
if (!existsSync4(configPath)) {
|
|
77230
77208
|
return {};
|
|
77231
77209
|
}
|
|
77232
77210
|
const encrypted = readFileSync3(configPath);
|
|
@@ -77254,11 +77232,11 @@ async function decryptConfig(identity) {
|
|
|
77254
77232
|
}
|
|
77255
77233
|
async function configGetAction(ctx, key, options = {}) {
|
|
77256
77234
|
const outputJson = options.json === true || ctx.format === "json";
|
|
77257
|
-
const
|
|
77258
|
-
if (!
|
|
77235
|
+
const identity = await getAgeKeyFrom1Password2();
|
|
77236
|
+
if (!identity) {
|
|
77259
77237
|
const result = {
|
|
77260
77238
|
success: false,
|
|
77261
|
-
error: "
|
|
77239
|
+
error: "OP_SERVICE_ACCOUNT_TOKEN not set. Required for encrypted config."
|
|
77262
77240
|
};
|
|
77263
77241
|
if (outputJson) {
|
|
77264
77242
|
ctx.output.data(result);
|
|
@@ -77269,7 +77247,6 @@ async function configGetAction(ctx, key, options = {}) {
|
|
|
77269
77247
|
return;
|
|
77270
77248
|
}
|
|
77271
77249
|
try {
|
|
77272
|
-
const identity = readFileSync3(keyPath, "utf8").trim();
|
|
77273
77250
|
const config = await decryptConfig(identity);
|
|
77274
77251
|
if (!(key in config)) {
|
|
77275
77252
|
const result2 = {
|
|
@@ -77312,11 +77289,26 @@ async function configGetAction(ctx, key, options = {}) {
|
|
|
77312
77289
|
|
|
77313
77290
|
// src/commands/config/list.ts
|
|
77314
77291
|
init_esm_shims();
|
|
77315
|
-
import { existsSync as
|
|
77292
|
+
import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
|
|
77316
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
|
+
}
|
|
77317
77309
|
async function decryptConfig2(identity) {
|
|
77318
77310
|
const configPath = getEncryptedConfigPath();
|
|
77319
|
-
if (!
|
|
77311
|
+
if (!existsSync5(configPath)) {
|
|
77320
77312
|
return {};
|
|
77321
77313
|
}
|
|
77322
77314
|
const encrypted = readFileSync4(configPath);
|
|
@@ -77344,11 +77336,11 @@ async function decryptConfig2(identity) {
|
|
|
77344
77336
|
}
|
|
77345
77337
|
async function configListAction(ctx, options = {}) {
|
|
77346
77338
|
const outputJson = options.json === true || ctx.format === "json";
|
|
77347
|
-
const
|
|
77348
|
-
if (!
|
|
77339
|
+
const identity = await getAgeKeyFrom1Password3();
|
|
77340
|
+
if (!identity) {
|
|
77349
77341
|
const result = {
|
|
77350
77342
|
success: false,
|
|
77351
|
-
error: "
|
|
77343
|
+
error: "OP_SERVICE_ACCOUNT_TOKEN not set. Required for encrypted config."
|
|
77352
77344
|
};
|
|
77353
77345
|
if (outputJson) {
|
|
77354
77346
|
ctx.output.data(result);
|
|
@@ -77359,7 +77351,6 @@ async function configListAction(ctx, options = {}) {
|
|
|
77359
77351
|
return;
|
|
77360
77352
|
}
|
|
77361
77353
|
try {
|
|
77362
|
-
const identity = readFileSync4(keyPath, "utf8").trim();
|
|
77363
77354
|
const config = await decryptConfig2(identity);
|
|
77364
77355
|
const keys = Object.keys(config);
|
|
77365
77356
|
if (keys.length === 0) {
|
|
@@ -77424,7 +77415,7 @@ var buildContext2 = async (command, json) => {
|
|
|
77424
77415
|
};
|
|
77425
77416
|
function registerConfigCommands(program3) {
|
|
77426
77417
|
const config = program3.command("config").description("Manage user-specific config overrides (encrypted)");
|
|
77427
|
-
config.command("init").description("
|
|
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) => {
|
|
77428
77419
|
const ctx = await buildContext2(command, options.json);
|
|
77429
77420
|
await configInitAction(ctx, options);
|
|
77430
77421
|
});
|
|
@@ -80114,7 +80105,7 @@ init_esm_shims();
|
|
|
80114
80105
|
// src/commands/eval-pipeline/run.ts
|
|
80115
80106
|
init_esm_shims();
|
|
80116
80107
|
import { createHash as createHash2 } from "crypto";
|
|
80117
|
-
import { existsSync as
|
|
80108
|
+
import { existsSync as existsSync6, mkdirSync, readFileSync as readFileSync5, rmSync, writeFileSync as writeFileSync4 } from "fs";
|
|
80118
80109
|
import { join as join5 } from "path";
|
|
80119
80110
|
import { readFile as readFile6 } from "fs/promises";
|
|
80120
80111
|
import { glob as glob4 } from "glob";
|
|
@@ -80532,7 +80523,7 @@ function getClassifySourceHash() {
|
|
|
80532
80523
|
join5(process.cwd(), "../core/src/pipeline/classify.ts")
|
|
80533
80524
|
];
|
|
80534
80525
|
for (const path of possiblePaths) {
|
|
80535
|
-
if (
|
|
80526
|
+
if (existsSync6(path)) {
|
|
80536
80527
|
const content = readFileSync5(path, "utf-8");
|
|
80537
80528
|
return createHash2("md5").update(content).digest("hex");
|
|
80538
80529
|
}
|
|
@@ -80544,7 +80535,7 @@ function getClassifySourceHash() {
|
|
|
80544
80535
|
function loadCachedClassify(cacheKey) {
|
|
80545
80536
|
const cachePath = join5(CACHE_DIR, `${cacheKey}.json`);
|
|
80546
80537
|
try {
|
|
80547
|
-
if (
|
|
80538
|
+
if (existsSync6(cachePath)) {
|
|
80548
80539
|
return JSON.parse(readFileSync5(cachePath, "utf-8"));
|
|
80549
80540
|
}
|
|
80550
80541
|
} catch {
|
|
@@ -80553,17 +80544,17 @@ function loadCachedClassify(cacheKey) {
|
|
|
80553
80544
|
}
|
|
80554
80545
|
function saveCachedClassify(cacheKey, result) {
|
|
80555
80546
|
try {
|
|
80556
|
-
if (!
|
|
80557
|
-
|
|
80547
|
+
if (!existsSync6(CACHE_DIR)) {
|
|
80548
|
+
mkdirSync(CACHE_DIR, { recursive: true });
|
|
80558
80549
|
}
|
|
80559
80550
|
const cachePath = join5(CACHE_DIR, `${cacheKey}.json`);
|
|
80560
|
-
|
|
80551
|
+
writeFileSync4(cachePath, JSON.stringify(result));
|
|
80561
80552
|
} catch {
|
|
80562
80553
|
}
|
|
80563
80554
|
}
|
|
80564
80555
|
function clearClassifyCache() {
|
|
80565
80556
|
try {
|
|
80566
|
-
if (
|
|
80557
|
+
if (existsSync6(CACHE_DIR)) {
|
|
80567
80558
|
rmSync(CACHE_DIR, { recursive: true, force: true });
|
|
80568
80559
|
}
|
|
80569
80560
|
} catch {
|
|
@@ -81555,7 +81546,7 @@ function registerEvalPipelineCommands(program3) {
|
|
|
81555
81546
|
|
|
81556
81547
|
// src/commands/eval-prompt.ts
|
|
81557
81548
|
init_esm_shims();
|
|
81558
|
-
import { existsSync as
|
|
81549
|
+
import { existsSync as existsSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
|
|
81559
81550
|
import { generateText as generateText2, stepCountIs as stepCountIs2, tool as tool4 } from "ai";
|
|
81560
81551
|
import { z as z5 } from "zod";
|
|
81561
81552
|
var leakPatterns = [
|
|
@@ -81742,7 +81733,7 @@ async function runEval2(ctx, options) {
|
|
|
81742
81733
|
try {
|
|
81743
81734
|
let prompt = SUPPORT_AGENT_PROMPT;
|
|
81744
81735
|
if (promptPath) {
|
|
81745
|
-
if (!
|
|
81736
|
+
if (!existsSync7(promptPath)) {
|
|
81746
81737
|
throw new CLIError({
|
|
81747
81738
|
userMessage: `Prompt file not found: ${promptPath}.`,
|
|
81748
81739
|
suggestion: "Verify the prompt path and try again."
|
|
@@ -81755,7 +81746,7 @@ async function runEval2(ctx, options) {
|
|
|
81755
81746
|
} else if (!outputJson) {
|
|
81756
81747
|
ctx.output.message("Using production prompt");
|
|
81757
81748
|
}
|
|
81758
|
-
if (!
|
|
81749
|
+
if (!existsSync7(datasetPath)) {
|
|
81759
81750
|
throw new CLIError({
|
|
81760
81751
|
userMessage: `Dataset not found: ${datasetPath}.`,
|
|
81761
81752
|
suggestion: "Provide a valid dataset file path."
|
|
@@ -81838,7 +81829,7 @@ async function runEval2(ctx, options) {
|
|
|
81838
81829
|
});
|
|
81839
81830
|
}
|
|
81840
81831
|
if (outputPath) {
|
|
81841
|
-
|
|
81832
|
+
writeFileSync5(outputPath, JSON.stringify(results, null, 2));
|
|
81842
81833
|
if (!outputJson) {
|
|
81843
81834
|
ctx.output.success(`Saved results to ${outputPath}`);
|
|
81844
81835
|
}
|
|
@@ -81867,7 +81858,7 @@ async function comparePrompts(ctx, options) {
|
|
|
81867
81858
|
try {
|
|
81868
81859
|
const baselinePrompt = baseline ? readFileSync6(baseline, "utf-8") : SUPPORT_AGENT_PROMPT;
|
|
81869
81860
|
const candidatePrompt = readFileSync6(candidate, "utf-8");
|
|
81870
|
-
if (!
|
|
81861
|
+
if (!existsSync7(datasetPath)) {
|
|
81871
81862
|
throw new CLIError({
|
|
81872
81863
|
userMessage: `Dataset not found: ${datasetPath}.`,
|
|
81873
81864
|
suggestion: "Provide a valid dataset file path."
|
|
@@ -82015,8 +82006,8 @@ init_esm_shims();
|
|
|
82015
82006
|
|
|
82016
82007
|
// src/commands/faq/classify.ts
|
|
82017
82008
|
init_esm_shims();
|
|
82018
|
-
import { appendFileSync, existsSync as
|
|
82019
|
-
import { dirname as
|
|
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";
|
|
82020
82011
|
import { generateObject } from "ai";
|
|
82021
82012
|
import { z as z6 } from "zod";
|
|
82022
82013
|
var PROJECT_ROOT = resolve3(__dirname, "../../../..");
|
|
@@ -82083,7 +82074,7 @@ async function loadConversationsFromParquet(parquetPath) {
|
|
|
82083
82074
|
}
|
|
82084
82075
|
function loadExistingClassifications(outputPath) {
|
|
82085
82076
|
const classifiedIds = /* @__PURE__ */ new Set();
|
|
82086
|
-
if (!
|
|
82077
|
+
if (!existsSync8(outputPath)) {
|
|
82087
82078
|
return classifiedIds;
|
|
82088
82079
|
}
|
|
82089
82080
|
const content = readFileSync7(outputPath, "utf-8");
|
|
@@ -82201,7 +82192,7 @@ async function faqClassify(ctx, options) {
|
|
|
82201
82192
|
ctx.output.data(` Dry run: ${options.dryRun ?? false}`);
|
|
82202
82193
|
ctx.output.data("");
|
|
82203
82194
|
}
|
|
82204
|
-
if (!
|
|
82195
|
+
if (!existsSync8(parquetPath)) {
|
|
82205
82196
|
handleFaqClassifyError(
|
|
82206
82197
|
ctx,
|
|
82207
82198
|
new CLIError({
|
|
@@ -82212,7 +82203,7 @@ async function faqClassify(ctx, options) {
|
|
|
82212
82203
|
);
|
|
82213
82204
|
return;
|
|
82214
82205
|
}
|
|
82215
|
-
if (!
|
|
82206
|
+
if (!existsSync8(taxonomyPath)) {
|
|
82216
82207
|
handleFaqClassifyError(
|
|
82217
82208
|
ctx,
|
|
82218
82209
|
new CLIError({
|
|
@@ -82223,9 +82214,9 @@ async function faqClassify(ctx, options) {
|
|
|
82223
82214
|
);
|
|
82224
82215
|
return;
|
|
82225
82216
|
}
|
|
82226
|
-
const outputDir =
|
|
82227
|
-
if (!
|
|
82228
|
-
|
|
82217
|
+
const outputDir = dirname2(outputPath);
|
|
82218
|
+
if (!existsSync8(outputDir)) {
|
|
82219
|
+
mkdirSync2(outputDir, { recursive: true });
|
|
82229
82220
|
}
|
|
82230
82221
|
if (!outputJson) ctx.output.data("\u{1F4DA} Loading taxonomy...");
|
|
82231
82222
|
const taxonomy = JSON.parse(readFileSync7(taxonomyPath, "utf-8"));
|
|
@@ -82393,18 +82384,18 @@ function registerFaqClassifyCommands(program3) {
|
|
|
82393
82384
|
|
|
82394
82385
|
// src/commands/faq/cluster.ts
|
|
82395
82386
|
init_esm_shims();
|
|
82396
|
-
import { existsSync as
|
|
82387
|
+
import { existsSync as existsSync10 } from "fs";
|
|
82397
82388
|
import { join as join9, resolve as resolve4 } from "path";
|
|
82398
82389
|
|
|
82399
82390
|
// ../core/src/faq/production-clusterer.ts
|
|
82400
82391
|
init_esm_shims();
|
|
82401
|
-
import { existsSync as
|
|
82392
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync3, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "fs";
|
|
82402
82393
|
import { join as join8 } from "path";
|
|
82403
82394
|
function readPhase0Assignments(phase0Path) {
|
|
82404
82395
|
const assignmentsPath = join8(phase0Path, "clusters/v1/assignments.json");
|
|
82405
|
-
if (!
|
|
82396
|
+
if (!existsSync9(assignmentsPath)) {
|
|
82406
82397
|
const latestPath = join8(phase0Path, "clusters/latest/assignments.json");
|
|
82407
|
-
if (!
|
|
82398
|
+
if (!existsSync9(latestPath)) {
|
|
82408
82399
|
throw new Error(`Phase 0 assignments not found at ${assignmentsPath}`);
|
|
82409
82400
|
}
|
|
82410
82401
|
const content2 = readFileSync8(latestPath, "utf-8");
|
|
@@ -82415,9 +82406,9 @@ function readPhase0Assignments(phase0Path) {
|
|
|
82415
82406
|
}
|
|
82416
82407
|
function readPhase0Labels(phase0Path) {
|
|
82417
82408
|
const labelsPath = join8(phase0Path, "clusters/v1/labels.json");
|
|
82418
|
-
if (!
|
|
82409
|
+
if (!existsSync9(labelsPath)) {
|
|
82419
82410
|
const latestPath = join8(phase0Path, "clusters/latest/labels.json");
|
|
82420
|
-
if (!
|
|
82411
|
+
if (!existsSync9(latestPath)) {
|
|
82421
82412
|
throw new Error(`Phase 0 labels not found at ${labelsPath}`);
|
|
82422
82413
|
}
|
|
82423
82414
|
const content2 = readFileSync8(latestPath, "utf-8");
|
|
@@ -82430,9 +82421,9 @@ function readPhase0Labels(phase0Path) {
|
|
|
82430
82421
|
}
|
|
82431
82422
|
function readPhase0Metrics(phase0Path) {
|
|
82432
82423
|
const metricsPath = join8(phase0Path, "clusters/v1/metrics.json");
|
|
82433
|
-
if (!
|
|
82424
|
+
if (!existsSync9(metricsPath)) {
|
|
82434
82425
|
const latestPath = join8(phase0Path, "clusters/latest/metrics.json");
|
|
82435
|
-
if (!
|
|
82426
|
+
if (!existsSync9(latestPath)) {
|
|
82436
82427
|
throw new Error(`Phase 0 metrics not found at ${metricsPath}`);
|
|
82437
82428
|
}
|
|
82438
82429
|
return JSON.parse(readFileSync8(latestPath, "utf-8"));
|
|
@@ -82553,17 +82544,17 @@ async function generateProductionClustering(options) {
|
|
|
82553
82544
|
}
|
|
82554
82545
|
function writeProductionArtifacts(result, outputPath) {
|
|
82555
82546
|
const versionPath = join8(outputPath, result.version);
|
|
82556
|
-
if (!
|
|
82557
|
-
|
|
82547
|
+
if (!existsSync9(versionPath)) {
|
|
82548
|
+
mkdirSync3(versionPath, { recursive: true });
|
|
82558
82549
|
}
|
|
82559
82550
|
const resultPath = join8(versionPath, "clustering-result.json");
|
|
82560
|
-
|
|
82551
|
+
writeFileSync6(resultPath, JSON.stringify(result, null, 2));
|
|
82561
82552
|
console.log(`\u2705 Written: ${resultPath}`);
|
|
82562
82553
|
const assignmentsPath = join8(versionPath, "assignments.json");
|
|
82563
|
-
|
|
82554
|
+
writeFileSync6(assignmentsPath, JSON.stringify(result.assignments, null, 2));
|
|
82564
82555
|
console.log(`\u2705 Written: ${assignmentsPath}`);
|
|
82565
82556
|
const clustersPath = join8(versionPath, "clusters.json");
|
|
82566
|
-
|
|
82557
|
+
writeFileSync6(
|
|
82567
82558
|
clustersPath,
|
|
82568
82559
|
JSON.stringify(
|
|
82569
82560
|
{
|
|
@@ -82589,14 +82580,14 @@ function writeProductionArtifacts(result, outputPath) {
|
|
|
82589
82580
|
priorityTier: c.priorityTier
|
|
82590
82581
|
}))
|
|
82591
82582
|
};
|
|
82592
|
-
|
|
82583
|
+
writeFileSync6(summaryPath, JSON.stringify(summary, null, 2));
|
|
82593
82584
|
console.log(`\u2705 Written: ${summaryPath}`);
|
|
82594
82585
|
const latestPath = join8(outputPath, "latest");
|
|
82595
|
-
if (
|
|
82586
|
+
if (existsSync9(latestPath)) {
|
|
82596
82587
|
const { rmSync: rmSync2 } = __require("fs");
|
|
82597
82588
|
rmSync2(latestPath, { recursive: true, force: true });
|
|
82598
82589
|
}
|
|
82599
|
-
|
|
82590
|
+
mkdirSync3(latestPath, { recursive: true });
|
|
82600
82591
|
for (const file of [
|
|
82601
82592
|
"clustering-result.json",
|
|
82602
82593
|
"assignments.json",
|
|
@@ -82605,7 +82596,7 @@ function writeProductionArtifacts(result, outputPath) {
|
|
|
82605
82596
|
]) {
|
|
82606
82597
|
const src = join8(versionPath, file);
|
|
82607
82598
|
const dst = join8(latestPath, file);
|
|
82608
|
-
|
|
82599
|
+
writeFileSync6(dst, readFileSync8(src));
|
|
82609
82600
|
}
|
|
82610
82601
|
console.log(`\u2705 Updated: ${latestPath}`);
|
|
82611
82602
|
}
|
|
@@ -82663,19 +82654,19 @@ function validatePaths(phase0Path) {
|
|
|
82663
82654
|
const assignmentsPath = join9(phase0Path, "clusters/v1/assignments.json");
|
|
82664
82655
|
const labelsPath = join9(phase0Path, "clusters/v1/labels.json");
|
|
82665
82656
|
const metricsPath = join9(phase0Path, "clusters/v1/metrics.json");
|
|
82666
|
-
if (!
|
|
82657
|
+
if (!existsSync10(assignmentsPath)) {
|
|
82667
82658
|
throw new CLIError({
|
|
82668
82659
|
userMessage: `Phase 0 assignments not found at ${assignmentsPath}.`,
|
|
82669
82660
|
suggestion: "Run Phase 0 clustering first or specify the correct --phase0-path."
|
|
82670
82661
|
});
|
|
82671
82662
|
}
|
|
82672
|
-
if (!
|
|
82663
|
+
if (!existsSync10(labelsPath)) {
|
|
82673
82664
|
throw new CLIError({
|
|
82674
82665
|
userMessage: `Phase 0 labels not found at ${labelsPath}.`,
|
|
82675
82666
|
suggestion: "Verify the --phase0-path points to valid artifacts."
|
|
82676
82667
|
});
|
|
82677
82668
|
}
|
|
82678
|
-
if (!
|
|
82669
|
+
if (!existsSync10(metricsPath)) {
|
|
82679
82670
|
throw new CLIError({
|
|
82680
82671
|
userMessage: `Phase 0 metrics not found at ${metricsPath}.`,
|
|
82681
82672
|
suggestion: "Verify the --phase0-path points to valid artifacts."
|
|
@@ -82756,12 +82747,12 @@ function registerFaqClusterCommands(program3) {
|
|
|
82756
82747
|
|
|
82757
82748
|
// src/commands/faq/extract.ts
|
|
82758
82749
|
init_esm_shims();
|
|
82759
|
-
import { existsSync as
|
|
82750
|
+
import { existsSync as existsSync12 } from "fs";
|
|
82760
82751
|
import { join as join11, resolve as resolve5 } from "path";
|
|
82761
82752
|
|
|
82762
82753
|
// ../core/src/faq/extractor.ts
|
|
82763
82754
|
init_esm_shims();
|
|
82764
|
-
import { existsSync as
|
|
82755
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync4, readFileSync as readFileSync9, writeFileSync as writeFileSync7 } from "fs";
|
|
82765
82756
|
import { join as join10 } from "path";
|
|
82766
82757
|
|
|
82767
82758
|
// ../core/src/faq/review.ts
|
|
@@ -83377,11 +83368,11 @@ async function extractFaqCandidates(options) {
|
|
|
83377
83368
|
}
|
|
83378
83369
|
function writeExtractionArtifacts(result, outputPath) {
|
|
83379
83370
|
const versionPath = join10(outputPath, result.version);
|
|
83380
|
-
if (!
|
|
83381
|
-
|
|
83371
|
+
if (!existsSync11(versionPath)) {
|
|
83372
|
+
mkdirSync4(versionPath, { recursive: true });
|
|
83382
83373
|
}
|
|
83383
83374
|
const resultPath = join10(versionPath, "extraction-result.json");
|
|
83384
|
-
|
|
83375
|
+
writeFileSync7(resultPath, JSON.stringify(result, null, 2));
|
|
83385
83376
|
console.log(`\u2705 Written: ${resultPath}`);
|
|
83386
83377
|
const candidatesPath = join10(versionPath, "candidates.json");
|
|
83387
83378
|
const candidatesData = {
|
|
@@ -83401,10 +83392,10 @@ function writeExtractionArtifacts(result, outputPath) {
|
|
|
83401
83392
|
sourceConversations: c.sourceConversations.slice(0, 5)
|
|
83402
83393
|
}))
|
|
83403
83394
|
};
|
|
83404
|
-
|
|
83395
|
+
writeFileSync7(candidatesPath, JSON.stringify(candidatesData, null, 2));
|
|
83405
83396
|
console.log(`\u2705 Written: ${candidatesPath}`);
|
|
83406
83397
|
const statsPath = join10(versionPath, "stats.json");
|
|
83407
|
-
|
|
83398
|
+
writeFileSync7(
|
|
83408
83399
|
statsPath,
|
|
83409
83400
|
JSON.stringify(
|
|
83410
83401
|
{
|
|
@@ -83418,11 +83409,11 @@ function writeExtractionArtifacts(result, outputPath) {
|
|
|
83418
83409
|
);
|
|
83419
83410
|
console.log(`\u2705 Written: ${statsPath}`);
|
|
83420
83411
|
const latestPath = join10(outputPath, "latest");
|
|
83421
|
-
if (
|
|
83412
|
+
if (existsSync11(latestPath)) {
|
|
83422
83413
|
const { rmSync: rmSync2 } = __require("fs");
|
|
83423
83414
|
rmSync2(latestPath, { recursive: true, force: true });
|
|
83424
83415
|
}
|
|
83425
|
-
|
|
83416
|
+
mkdirSync4(latestPath, { recursive: true });
|
|
83426
83417
|
for (const file of [
|
|
83427
83418
|
"extraction-result.json",
|
|
83428
83419
|
"candidates.json",
|
|
@@ -83430,8 +83421,8 @@ function writeExtractionArtifacts(result, outputPath) {
|
|
|
83430
83421
|
]) {
|
|
83431
83422
|
const src = join10(versionPath, file);
|
|
83432
83423
|
const dst = join10(latestPath, file);
|
|
83433
|
-
if (
|
|
83434
|
-
|
|
83424
|
+
if (existsSync11(src)) {
|
|
83425
|
+
writeFileSync7(dst, readFileSync9(src));
|
|
83435
83426
|
}
|
|
83436
83427
|
}
|
|
83437
83428
|
console.log(`\u2705 Updated: ${latestPath}`);
|
|
@@ -83495,13 +83486,13 @@ var DEFAULT_GOLDEN_PATH = join11(
|
|
|
83495
83486
|
var DEFAULT_OUTPUT_PATH3 = join11(PROJECT_ROOT3, "artifacts/phase-1/extraction");
|
|
83496
83487
|
var DEFAULT_CACHE_PATH = `${process.env.HOME}/skill/data/front-cache.db`;
|
|
83497
83488
|
function validatePaths2(ctx, clusteringPath, goldenPath, outputJson) {
|
|
83498
|
-
if (!
|
|
83489
|
+
if (!existsSync12(clusteringPath)) {
|
|
83499
83490
|
throw new CLIError({
|
|
83500
83491
|
userMessage: `Clustering result not found at ${clusteringPath}.`,
|
|
83501
83492
|
suggestion: "Run `bun src/index.ts faq cluster` first to generate clustering."
|
|
83502
83493
|
});
|
|
83503
83494
|
}
|
|
83504
|
-
if (goldenPath && !
|
|
83495
|
+
if (goldenPath && !existsSync12(goldenPath)) {
|
|
83505
83496
|
if (!outputJson) {
|
|
83506
83497
|
ctx.output.warn(`Golden responses not found at ${goldenPath}`);
|
|
83507
83498
|
ctx.output.warn("Golden matching will be disabled.");
|
|
@@ -83530,7 +83521,7 @@ async function faqExtract(ctx, options) {
|
|
|
83530
83521
|
ctx.output.data("");
|
|
83531
83522
|
}
|
|
83532
83523
|
validatePaths2(ctx, clusteringPath, goldenPath, outputJson);
|
|
83533
|
-
if (!
|
|
83524
|
+
if (!existsSync12(cachePath)) {
|
|
83534
83525
|
const cliError = new CLIError({
|
|
83535
83526
|
userMessage: `DuckDB cache not found at ${cachePath}.`,
|
|
83536
83527
|
suggestion: "Run `bun src/index.ts front-cache sync` first to populate cache."
|
|
@@ -83552,7 +83543,7 @@ async function faqExtract(ctx, options) {
|
|
|
83552
83543
|
}
|
|
83553
83544
|
const extractionOptions = {
|
|
83554
83545
|
clusteringPath,
|
|
83555
|
-
goldenPath:
|
|
83546
|
+
goldenPath: existsSync12(goldenPath) ? goldenPath : void 0,
|
|
83556
83547
|
source,
|
|
83557
83548
|
outputPath,
|
|
83558
83549
|
version,
|
|
@@ -83672,7 +83663,7 @@ function registerFaqExtractCommands(program3) {
|
|
|
83672
83663
|
|
|
83673
83664
|
// src/commands/faq/mine.ts
|
|
83674
83665
|
init_esm_shims();
|
|
83675
|
-
import { writeFileSync as
|
|
83666
|
+
import { writeFileSync as writeFileSync8 } from "fs";
|
|
83676
83667
|
|
|
83677
83668
|
// ../core/src/faq/index.ts
|
|
83678
83669
|
init_esm_shims();
|
|
@@ -92489,7 +92480,7 @@ async function faqMine(ctx, options) {
|
|
|
92489
92480
|
}))
|
|
92490
92481
|
};
|
|
92491
92482
|
if (options.export) {
|
|
92492
|
-
|
|
92483
|
+
writeFileSync8(options.export, JSON.stringify(rawData, null, 2), "utf-8");
|
|
92493
92484
|
if (outputJson) {
|
|
92494
92485
|
ctx.output.data({
|
|
92495
92486
|
success: true,
|
|
@@ -92563,7 +92554,7 @@ async function faqMine(ctx, options) {
|
|
|
92563
92554
|
generatedAt: c.generatedAt.toISOString()
|
|
92564
92555
|
}))
|
|
92565
92556
|
};
|
|
92566
|
-
|
|
92557
|
+
writeFileSync8(
|
|
92567
92558
|
options.export,
|
|
92568
92559
|
JSON.stringify(exportData, null, 2),
|
|
92569
92560
|
"utf-8"
|
|
@@ -92626,7 +92617,7 @@ function registerFaqMineCommands(program3) {
|
|
|
92626
92617
|
// src/commands/faq/review.ts
|
|
92627
92618
|
init_esm_shims();
|
|
92628
92619
|
import { spawnSync } from "child_process";
|
|
92629
|
-
import { existsSync as
|
|
92620
|
+
import { existsSync as existsSync13, readFileSync as readFileSync10, unlinkSync, writeFileSync as writeFileSync9 } from "fs";
|
|
92630
92621
|
import { tmpdir } from "os";
|
|
92631
92622
|
import { join as join12 } from "path";
|
|
92632
92623
|
import { confirm as confirm2, select as select3 } from "@inquirer/prompts";
|
|
@@ -92704,7 +92695,7 @@ Save and close the editor when done.
|
|
|
92704
92695
|
The sections are separated by "## Question" and "## Answer" headers.
|
|
92705
92696
|
-->
|
|
92706
92697
|
`;
|
|
92707
|
-
|
|
92698
|
+
writeFileSync9(tmpFile, content, "utf-8");
|
|
92708
92699
|
try {
|
|
92709
92700
|
const result = spawnSync(editor, [tmpFile], {
|
|
92710
92701
|
stdio: "inherit",
|
|
@@ -92732,7 +92723,7 @@ The sections are separated by "## Question" and "## Answer" headers.
|
|
|
92732
92723
|
answer: editedAnswer
|
|
92733
92724
|
};
|
|
92734
92725
|
} finally {
|
|
92735
|
-
if (
|
|
92726
|
+
if (existsSync13(tmpFile)) {
|
|
92736
92727
|
unlinkSync(tmpFile);
|
|
92737
92728
|
}
|
|
92738
92729
|
}
|
|
@@ -94927,7 +94918,7 @@ function registerInboxCommand(front) {
|
|
|
94927
94918
|
|
|
94928
94919
|
// src/commands/front/pull-conversations.ts
|
|
94929
94920
|
init_esm_shims();
|
|
94930
|
-
import { writeFileSync as
|
|
94921
|
+
import { writeFileSync as writeFileSync10 } from "fs";
|
|
94931
94922
|
async function pullConversations(ctx, options) {
|
|
94932
94923
|
const { inbox, limit: limit2 = 50, output, filter: filter4 } = options;
|
|
94933
94924
|
const outputJson = options.json === true || ctx.format === "json";
|
|
@@ -95060,7 +95051,7 @@ Built ${samples.length} eval samples`);
|
|
|
95060
95051
|
ctx.output.data(` ${cat}: ${count}`);
|
|
95061
95052
|
}
|
|
95062
95053
|
if (output) {
|
|
95063
|
-
|
|
95054
|
+
writeFileSync10(output, JSON.stringify(samples, null, 2));
|
|
95064
95055
|
ctx.output.data(`
|
|
95065
95056
|
Saved to ${output}`);
|
|
95066
95057
|
} else if (outputJson) {
|
|
@@ -103241,7 +103232,7 @@ var compile3 = wrapCompile(compile2);
|
|
|
103241
103232
|
var _compileUnsafe = wrapCompile(compileUnsafe);
|
|
103242
103233
|
var _compileToken = wrapCompile(compileToken);
|
|
103243
103234
|
function getSelectorFunc(searchFunc) {
|
|
103244
|
-
return function
|
|
103235
|
+
return function select7(query, elements, options) {
|
|
103245
103236
|
const opts = convertOptionFormats(options);
|
|
103246
103237
|
if (typeof query !== "function") {
|
|
103247
103238
|
query = compileUnsafe(query, opts, elements);
|
|
@@ -113895,10 +113886,217 @@ function registerKbCommands(program3) {
|
|
|
113895
113886
|
});
|
|
113896
113887
|
}
|
|
113897
113888
|
|
|
113898
|
-
// src/commands/
|
|
113889
|
+
// src/commands/keys/index.ts
|
|
113899
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
|
+
}
|
|
113900
114098
|
|
|
113901
|
-
// src/commands/linear/
|
|
114099
|
+
// src/commands/linear/index.ts
|
|
113902
114100
|
init_esm_shims();
|
|
113903
114101
|
|
|
113904
114102
|
// src/core/write-gate.ts
|
|
@@ -113911,11 +114109,14 @@ function requirePersonalKey(keyName) {
|
|
|
113911
114109
|
throw new CLIError({
|
|
113912
114110
|
userMessage: `Write operations require a personal API key for ${keyName}.`,
|
|
113913
114111
|
exitCode: EXIT_CODES.auth,
|
|
113914
|
-
suggestion: "Run 'skill
|
|
114112
|
+
suggestion: "Run 'skill keys add' to set up your personal keys.",
|
|
113915
114113
|
debugMessage: `Key provenance for ${keyName}: ${provenance ?? "undefined"}`
|
|
113916
114114
|
});
|
|
113917
114115
|
}
|
|
113918
114116
|
|
|
114117
|
+
// src/commands/linear/assign.ts
|
|
114118
|
+
init_esm_shims();
|
|
114119
|
+
|
|
113919
114120
|
// src/commands/linear/client.ts
|
|
113920
114121
|
init_esm_shims();
|
|
113921
114122
|
import { LinearClient } from "@linear/sdk";
|
|
@@ -113947,8 +114148,8 @@ function hateoasWrap2(opts) {
|
|
|
113947
114148
|
return response;
|
|
113948
114149
|
}
|
|
113949
114150
|
var WRITE_ACTION_META = {
|
|
113950
|
-
personal_key_hint: "\u26A0\uFE0F Write operations require a personal LINEAR_API_KEY. Run `skill
|
|
113951
|
-
setup_command: "skill
|
|
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"
|
|
113952
114153
|
};
|
|
113953
114154
|
function issueLinks(identifier, teamKey) {
|
|
113954
114155
|
const links = [
|
|
@@ -114809,7 +115010,7 @@ async function getIssue(ctx, id) {
|
|
|
114809
115010
|
ctx.output.data(` \u2022 Close: skill linear close ${issue.identifier}`);
|
|
114810
115011
|
ctx.output.data("");
|
|
114811
115012
|
ctx.output.data(" \u26A0\uFE0F Write operations require a personal LINEAR_API_KEY.");
|
|
114812
|
-
ctx.output.data(" Run `skill
|
|
115013
|
+
ctx.output.data(" Run `skill keys add` to set up your keys.");
|
|
114813
115014
|
ctx.output.data("");
|
|
114814
115015
|
} catch (error) {
|
|
114815
115016
|
const cliError = error instanceof CLIError ? error : new CLIError({
|
|
@@ -116117,7 +116318,9 @@ Quick start:
|
|
|
116117
116318
|
skill linear create "Title" Create issue
|
|
116118
116319
|
skill linear search "query" Search issues
|
|
116119
116320
|
|
|
116120
|
-
All commands support --json for machine-readable output
|
|
116321
|
+
All commands support --json for machine-readable output.
|
|
116322
|
+
|
|
116323
|
+
\u26A0\uFE0F Write operations require personal LINEAR_API_KEY (run 'skill keys add').`
|
|
116121
116324
|
);
|
|
116122
116325
|
linear.command("issues").description(
|
|
116123
116326
|
`List issues with optional filters
|
|
@@ -116147,6 +116350,7 @@ Examples:
|
|
|
116147
116350
|
skill linear my --state "In Progress" Only in-progress
|
|
116148
116351
|
skill linear my --limit 5 Just top 5`
|
|
116149
116352
|
).option("--limit <number>", "Maximum results (default: 20)", "20").option("--state <name>", "Filter by state name").option("--json", "Output as JSON with HATEOAS links").action(async (options, command) => {
|
|
116353
|
+
requirePersonalKey("LINEAR_API_KEY");
|
|
116150
116354
|
const ctx = await contextFromCommand2(command, options);
|
|
116151
116355
|
await listMyIssues(ctx, {
|
|
116152
116356
|
limit: parseInt(options.limit || "20", 10),
|
|
@@ -116191,6 +116395,7 @@ Priority: 0=Urgent, 1=High, 2=Medium, 3=Low, 4=None`
|
|
|
116191
116395
|
(v, p) => [...p, v],
|
|
116192
116396
|
[]
|
|
116193
116397
|
).option("--project <name>", "Project name").option("--estimate <points>", "Estimate in points").option("--due-date <YYYY-MM-DD>", "Due date").option("--json", "Output as JSON with HATEOAS links").action(async (title, options, command) => {
|
|
116398
|
+
requirePersonalKey("LINEAR_API_KEY");
|
|
116194
116399
|
const ctx = await contextFromCommand2(command, options);
|
|
116195
116400
|
await createIssue(ctx, title, {
|
|
116196
116401
|
description: options.description,
|
|
@@ -116211,6 +116416,7 @@ Examples:
|
|
|
116211
116416
|
skill linear update ENG-123 --priority 1 --estimate 3
|
|
116212
116417
|
skill linear update ENG-123 --due-date 2024-03-15`
|
|
116213
116418
|
).argument("<id>", "Issue identifier").option("--title <text>", "New title").option("--description <text>", "New description").option("--priority <0-4>", "New priority").option("--estimate <points>", "New estimate").option("--due-date <YYYY-MM-DD>", "New due date").option("--project <name>", "Move to project").option("--json", "Output as JSON with HATEOAS links").action(async (id, options, command) => {
|
|
116419
|
+
requirePersonalKey("LINEAR_API_KEY");
|
|
116214
116420
|
const ctx = await contextFromCommand2(command, options);
|
|
116215
116421
|
await updateIssue(ctx, id, {
|
|
116216
116422
|
title: options.title,
|
|
@@ -116229,6 +116435,7 @@ Examples:
|
|
|
116229
116435
|
skill linear assign ENG-123 --to me
|
|
116230
116436
|
skill linear assign ENG-123 --unassign`
|
|
116231
116437
|
).argument("<id>", "Issue identifier").option("--to <email>", 'Assign to user email (or "me")').option("--unassign", "Remove assignee").option("--json", "Output as JSON with HATEOAS links").action(async (id, options, command) => {
|
|
116438
|
+
requirePersonalKey("LINEAR_API_KEY");
|
|
116232
116439
|
const ctx = await contextFromCommand2(command, options);
|
|
116233
116440
|
await assignIssue(ctx, id, {
|
|
116234
116441
|
to: options.to,
|
|
@@ -116244,6 +116451,7 @@ Examples:
|
|
|
116244
116451
|
|
|
116245
116452
|
Use 'skill linear states <team>' to see available states.`
|
|
116246
116453
|
).argument("<id>", "Issue identifier").requiredOption("--state <name>", "Target state name").option("--json", "Output as JSON with HATEOAS links").action(async (id, options, command) => {
|
|
116454
|
+
requirePersonalKey("LINEAR_API_KEY");
|
|
116247
116455
|
const ctx = await contextFromCommand2(command, options);
|
|
116248
116456
|
await changeState(ctx, id, { state: options.state });
|
|
116249
116457
|
});
|
|
@@ -116254,6 +116462,7 @@ Examples:
|
|
|
116254
116462
|
skill linear close ENG-123 Close as done
|
|
116255
116463
|
skill linear close ENG-123 --canceled Cancel the issue`
|
|
116256
116464
|
).argument("<id>", "Issue identifier").option("--canceled", "Close as canceled instead of done").option("--json", "Output as JSON with HATEOAS links").action(async (id, options, command) => {
|
|
116465
|
+
requirePersonalKey("LINEAR_API_KEY");
|
|
116257
116466
|
const ctx = await contextFromCommand2(command, options);
|
|
116258
116467
|
await closeIssue(ctx, id, { canceled: options.canceled });
|
|
116259
116468
|
});
|
|
@@ -116277,6 +116486,7 @@ Use 'skill linear labels <team>' to see available labels.`
|
|
|
116277
116486
|
(v, p) => [...p, v],
|
|
116278
116487
|
[]
|
|
116279
116488
|
).option("--json", "Output as JSON with HATEOAS links").action(async (id, options, command) => {
|
|
116489
|
+
requirePersonalKey("LINEAR_API_KEY");
|
|
116280
116490
|
const ctx = await contextFromCommand2(command, options);
|
|
116281
116491
|
await modifyLabels(ctx, id, {
|
|
116282
116492
|
add: options.add,
|
|
@@ -116292,6 +116502,7 @@ Examples:
|
|
|
116292
116502
|
skill linear link ENG-123 --related ENG-456
|
|
116293
116503
|
skill linear link ENG-123 --duplicate ENG-456`
|
|
116294
116504
|
).argument("<id>", "Source issue identifier").option("--blocks <id>", "This issue blocks <id>").option("--blocked-by <id>", "This issue is blocked by <id>").option("--related <id>", "Related to <id>").option("--duplicate <id>", "Duplicate of <id>").option("--json", "Output as JSON with HATEOAS links").action(async (id, options, command) => {
|
|
116505
|
+
requirePersonalKey("LINEAR_API_KEY");
|
|
116295
116506
|
const ctx = await contextFromCommand2(command, options);
|
|
116296
116507
|
await linkIssues(ctx, id, {
|
|
116297
116508
|
blocks: options.blocks,
|
|
@@ -116307,6 +116518,7 @@ Examples:
|
|
|
116307
116518
|
skill linear comment ENG-123 --body "Great work!"
|
|
116308
116519
|
skill linear comment ENG-123 --body "## Update\\n- Item 1\\n- Item 2"`
|
|
116309
116520
|
).argument("<id>", "Issue identifier").requiredOption("--body <text>", "Comment text (supports markdown)").option("--json", "Output as JSON with HATEOAS links").action(async (id, options, command) => {
|
|
116521
|
+
requirePersonalKey("LINEAR_API_KEY");
|
|
116310
116522
|
const ctx = await contextFromCommand2(command, options);
|
|
116311
116523
|
await addComment(ctx, id, { body: options.body });
|
|
116312
116524
|
});
|
|
@@ -116738,7 +116950,7 @@ async function deleteMemory(ctx, id, options) {
|
|
|
116738
116950
|
}
|
|
116739
116951
|
|
|
116740
116952
|
// src/commands/memory/index.ts
|
|
116741
|
-
var
|
|
116953
|
+
var buildContext5 = async (command, json) => {
|
|
116742
116954
|
const opts = typeof command.optsWithGlobals === "function" ? command.optsWithGlobals() : {
|
|
116743
116955
|
...command.parent?.opts(),
|
|
116744
116956
|
...command.opts()
|
|
@@ -116752,42 +116964,42 @@ var buildContext4 = async (command, json) => {
|
|
|
116752
116964
|
function registerMemoryCommands(program3) {
|
|
116753
116965
|
const memory = program3.command("memory").description("Manage semantic memory for agent learning");
|
|
116754
116966
|
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) => {
|
|
116755
|
-
const ctx = await
|
|
116967
|
+
const ctx = await buildContext5(command, options.json);
|
|
116756
116968
|
await store(ctx, content, options);
|
|
116757
116969
|
});
|
|
116758
116970
|
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(
|
|
116759
116971
|
"--min-confidence <confidence>",
|
|
116760
116972
|
"Minimum confidence threshold (0-1, default: 0.5)"
|
|
116761
116973
|
).option("--json", "Output as JSON").action(async (query, options, command) => {
|
|
116762
|
-
const ctx = await
|
|
116974
|
+
const ctx = await buildContext5(command, options.json);
|
|
116763
116975
|
await find5(ctx, query, options);
|
|
116764
116976
|
});
|
|
116765
116977
|
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) => {
|
|
116766
|
-
const ctx = await
|
|
116978
|
+
const ctx = await buildContext5(command, options.json);
|
|
116767
116979
|
await get2(ctx, id, options);
|
|
116768
116980
|
});
|
|
116769
116981
|
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) => {
|
|
116770
|
-
const ctx = await
|
|
116982
|
+
const ctx = await buildContext5(command, options.json);
|
|
116771
116983
|
await validate2(ctx, id, options);
|
|
116772
116984
|
});
|
|
116773
116985
|
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) => {
|
|
116774
|
-
const ctx = await
|
|
116986
|
+
const ctx = await buildContext5(command, options.json);
|
|
116775
116987
|
await upvote(ctx, id, options);
|
|
116776
116988
|
});
|
|
116777
116989
|
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) => {
|
|
116778
|
-
const ctx = await
|
|
116990
|
+
const ctx = await buildContext5(command, options.json);
|
|
116779
116991
|
await downvote(ctx, id, options);
|
|
116780
116992
|
});
|
|
116781
116993
|
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) => {
|
|
116782
|
-
const ctx = await
|
|
116994
|
+
const ctx = await buildContext5(command, options.json);
|
|
116783
116995
|
await deleteMemory(ctx, id, options);
|
|
116784
116996
|
});
|
|
116785
116997
|
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) => {
|
|
116786
|
-
const ctx = await
|
|
116998
|
+
const ctx = await buildContext5(command, options.json);
|
|
116787
116999
|
await stats3(ctx, options);
|
|
116788
117000
|
});
|
|
116789
117001
|
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) => {
|
|
116790
|
-
const ctx = await
|
|
117002
|
+
const ctx = await buildContext5(command, options.json);
|
|
116791
117003
|
await stale(ctx, options);
|
|
116792
117004
|
});
|
|
116793
117005
|
}
|
|
@@ -117369,7 +117581,7 @@ async function buildValidateDatasetFromProduction(productionResultsPath, outputP
|
|
|
117369
117581
|
}
|
|
117370
117582
|
|
|
117371
117583
|
// src/commands/pipeline.ts
|
|
117372
|
-
var
|
|
117584
|
+
var buildContext6 = async (command, json) => {
|
|
117373
117585
|
const opts = typeof command.optsWithGlobals === "function" ? command.optsWithGlobals() : {
|
|
117374
117586
|
...command.parent?.opts(),
|
|
117375
117587
|
...command.opts()
|
|
@@ -117440,7 +117652,7 @@ function registerPipelineCommands(program3) {
|
|
|
117440
117652
|
"Model for LLM classification",
|
|
117441
117653
|
"anthropic/claude-haiku-4-5"
|
|
117442
117654
|
).action(async (opts, command) => {
|
|
117443
|
-
const ctx = await
|
|
117655
|
+
const ctx = await buildContext6(command, opts.json);
|
|
117444
117656
|
try {
|
|
117445
117657
|
await runClassifyEval2({
|
|
117446
117658
|
...opts,
|
|
@@ -117451,7 +117663,7 @@ function registerPipelineCommands(program3) {
|
|
|
117451
117663
|
}
|
|
117452
117664
|
});
|
|
117453
117665
|
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) => {
|
|
117454
|
-
const ctx = await
|
|
117666
|
+
const ctx = await buildContext6(command);
|
|
117455
117667
|
try {
|
|
117456
117668
|
await buildClassifyDataset(opts.production, opts.output);
|
|
117457
117669
|
ctx.output.success(`Dataset written to ${opts.output}`);
|
|
@@ -117463,7 +117675,7 @@ function registerPipelineCommands(program3) {
|
|
|
117463
117675
|
"--dataset <file>",
|
|
117464
117676
|
"Path to scenarios JSON (uses built-in if not provided)"
|
|
117465
117677
|
).option("--output <file>", "Save results to JSON").option("--verbose", "Show individual failures").option("--json", "JSON output").action(async (opts, command) => {
|
|
117466
|
-
const ctx = await
|
|
117678
|
+
const ctx = await buildContext6(command, opts.json);
|
|
117467
117679
|
try {
|
|
117468
117680
|
await runValidateEval2({
|
|
117469
117681
|
...opts,
|
|
@@ -117474,7 +117686,7 @@ function registerPipelineCommands(program3) {
|
|
|
117474
117686
|
}
|
|
117475
117687
|
});
|
|
117476
117688
|
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) => {
|
|
117477
|
-
const ctx = await
|
|
117689
|
+
const ctx = await buildContext6(command);
|
|
117478
117690
|
try {
|
|
117479
117691
|
await buildValidateDatasetFromProduction(opts.production, opts.output);
|
|
117480
117692
|
ctx.output.success(`Dataset written to ${opts.output}`);
|
|
@@ -117487,7 +117699,7 @@ function registerPipelineCommands(program3) {
|
|
|
117487
117699
|
"Model for LLM steps",
|
|
117488
117700
|
"anthropic/claude-haiku-4-5"
|
|
117489
117701
|
).action(async (opts, command) => {
|
|
117490
|
-
const ctx = await
|
|
117702
|
+
const ctx = await buildContext6(command, opts.json);
|
|
117491
117703
|
try {
|
|
117492
117704
|
await runE2EEval2({ ...opts, json: opts.json ?? ctx.format === "json" });
|
|
117493
117705
|
} catch (error) {
|
|
@@ -117495,7 +117707,7 @@ function registerPipelineCommands(program3) {
|
|
|
117495
117707
|
}
|
|
117496
117708
|
});
|
|
117497
117709
|
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) => {
|
|
117498
|
-
const ctx = await
|
|
117710
|
+
const ctx = await buildContext6(command, opts.json);
|
|
117499
117711
|
await runPipelineCommand(ctx, opts);
|
|
117500
117712
|
});
|
|
117501
117713
|
}
|
|
@@ -117503,10 +117715,10 @@ function registerPipelineCommands(program3) {
|
|
|
117503
117715
|
// src/commands/plugin-sync.ts
|
|
117504
117716
|
init_esm_shims();
|
|
117505
117717
|
import { homedir as homedir3 } from "os";
|
|
117506
|
-
import { dirname as
|
|
117718
|
+
import { dirname as dirname3, join as join13, resolve as resolve6 } from "path";
|
|
117507
117719
|
import { fileURLToPath } from "url";
|
|
117508
117720
|
var PLUGIN_SOURCE_DIR = resolve6(
|
|
117509
|
-
|
|
117721
|
+
dirname3(fileURLToPath(import.meta.url)),
|
|
117510
117722
|
"../../plugin"
|
|
117511
117723
|
);
|
|
117512
117724
|
var PLUGIN_MANIFEST_RELATIVE = join13(".claude-plugin", "plugin.json");
|
|
@@ -117612,7 +117824,7 @@ var registerPluginSyncCommand = (program3) => {
|
|
|
117612
117824
|
|
|
117613
117825
|
// src/commands/responses.ts
|
|
117614
117826
|
init_esm_shims();
|
|
117615
|
-
import { writeFileSync as
|
|
117827
|
+
import { writeFileSync as writeFileSync11 } from "fs";
|
|
117616
117828
|
function formatDate3(date) {
|
|
117617
117829
|
return date.toLocaleString("en-US", {
|
|
117618
117830
|
month: "short",
|
|
@@ -118145,7 +118357,7 @@ async function exportResponses(ctx, options) {
|
|
|
118145
118357
|
}
|
|
118146
118358
|
const outputJson = JSON.stringify(exportData, null, 2);
|
|
118147
118359
|
if (options.output) {
|
|
118148
|
-
|
|
118360
|
+
writeFileSync11(options.output, outputJson, "utf-8");
|
|
118149
118361
|
if (!outputJsonFormat) {
|
|
118150
118362
|
ctx.output.success(
|
|
118151
118363
|
`Exported ${exportData.length} responses to ${options.output}`
|
|
@@ -118794,7 +119006,7 @@ init_esm_shims();
|
|
|
118794
119006
|
import { spawn } from "child_process";
|
|
118795
119007
|
import { writeFile as writeFile7 } from "fs/promises";
|
|
118796
119008
|
import { homedir as homedir4 } from "os";
|
|
118797
|
-
import { dirname as
|
|
119009
|
+
import { dirname as dirname4, join as join14 } from "path";
|
|
118798
119010
|
var CONFIG_DIR_NAME = "skill-cli";
|
|
118799
119011
|
var AUTO_UPDATE_STATE_FILE = "auto-update.json";
|
|
118800
119012
|
var DEFAULT_PACKAGE = "@skillrecordings/cli";
|
|
@@ -118824,7 +119036,7 @@ var AutoUpdateStore = class {
|
|
|
118824
119036
|
}
|
|
118825
119037
|
async save(state) {
|
|
118826
119038
|
try {
|
|
118827
|
-
await ensureDir(
|
|
119039
|
+
await ensureDir(dirname4(this.filePath));
|
|
118828
119040
|
await writeFile7(this.filePath, JSON.stringify(state, null, 2), "utf-8");
|
|
118829
119041
|
} catch {
|
|
118830
119042
|
}
|
|
@@ -119030,7 +119242,7 @@ var DEFAULT_HINT_RULES = [
|
|
|
119030
119242
|
{
|
|
119031
119243
|
id: "onboarding.auth",
|
|
119032
119244
|
audience: "onboarding",
|
|
119033
|
-
message: "Set up
|
|
119245
|
+
message: "Set up your own API keys with `skill keys`.",
|
|
119034
119246
|
showWhen: (state) => state.totalRuns >= 1 && !hasMilestone(state, "auth_configured"),
|
|
119035
119247
|
retireWhen: (state) => hasMilestone(state, "auth_configured")
|
|
119036
119248
|
},
|
|
@@ -119062,6 +119274,13 @@ var DEFAULT_HINT_RULES = [
|
|
|
119062
119274
|
showWhen: (state) => state.totalRuns >= 3 && !hasCommandPrefix(state, "axiom."),
|
|
119063
119275
|
retireWhen: (state) => hasCommandPrefix(state, "axiom.")
|
|
119064
119276
|
},
|
|
119277
|
+
{
|
|
119278
|
+
id: "discovery.keys",
|
|
119279
|
+
audience: "discovery",
|
|
119280
|
+
message: "Override shared credentials with your own: `skill keys add`",
|
|
119281
|
+
showWhen: (state) => state.totalRuns >= 3 && !hasCommand(state, "keys") && !hasMilestone(state, "auth_configured"),
|
|
119282
|
+
retireWhen: (state) => hasCommand(state, "keys") || hasCommand(state, "keys.add") || hasMilestone(state, "auth_configured")
|
|
119283
|
+
},
|
|
119065
119284
|
{
|
|
119066
119285
|
id: "context.front.triage",
|
|
119067
119286
|
audience: "contextual",
|
|
@@ -119132,10 +119351,10 @@ var writeHints = (hints, stderr) => {
|
|
|
119132
119351
|
init_esm_shims();
|
|
119133
119352
|
import { lstat, readlink, symlink } from "fs/promises";
|
|
119134
119353
|
import { homedir as homedir5 } from "os";
|
|
119135
|
-
import { dirname as
|
|
119354
|
+
import { dirname as dirname5, join as join15, resolve as resolve7 } from "path";
|
|
119136
119355
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
119137
119356
|
var SKILL_SOURCE_DIR = resolve7(
|
|
119138
|
-
|
|
119357
|
+
dirname5(fileURLToPath2(import.meta.url)),
|
|
119139
119358
|
"../../../../.claude/skills/skill-cli"
|
|
119140
119359
|
);
|
|
119141
119360
|
var SKILL_TARGET_DIR = join15(homedir5(), ".claude", "skills", "skill-cli");
|
|
@@ -119149,7 +119368,7 @@ async function autoLinkSkill() {
|
|
|
119149
119368
|
} catch (e) {
|
|
119150
119369
|
if (e.code === "ENOENT") {
|
|
119151
119370
|
const { mkdir: mkdir2 } = await import("fs/promises");
|
|
119152
|
-
await mkdir2(
|
|
119371
|
+
await mkdir2(dirname5(target), { recursive: true });
|
|
119153
119372
|
await symlink(source, target, "dir");
|
|
119154
119373
|
return {
|
|
119155
119374
|
status: "linked",
|
|
@@ -119162,7 +119381,7 @@ async function autoLinkSkill() {
|
|
|
119162
119381
|
}
|
|
119163
119382
|
if (stats4.isSymbolicLink()) {
|
|
119164
119383
|
const linkTarget = await readlink(target);
|
|
119165
|
-
const resolvedLinkTarget = resolve7(
|
|
119384
|
+
const resolvedLinkTarget = resolve7(dirname5(target), linkTarget);
|
|
119166
119385
|
if (resolvedLinkTarget === source || linkTarget === source) {
|
|
119167
119386
|
return {
|
|
119168
119387
|
status: "exists",
|
|
@@ -119242,7 +119461,7 @@ async function sendTelemetryEvent(event) {
|
|
|
119242
119461
|
init_esm_shims();
|
|
119243
119462
|
import { writeFile as writeFile8 } from "fs/promises";
|
|
119244
119463
|
import { homedir as homedir6 } from "os";
|
|
119245
|
-
import { dirname as
|
|
119464
|
+
import { dirname as dirname6, join as join16 } from "path";
|
|
119246
119465
|
var CONFIG_DIR_NAME2 = "skill-cli";
|
|
119247
119466
|
var USAGE_FILE_NAME = "usage.json";
|
|
119248
119467
|
function resolveConfigDir2(configDir) {
|
|
@@ -119312,7 +119531,7 @@ var UsageTracker = class {
|
|
|
119312
119531
|
}
|
|
119313
119532
|
async saveState(state) {
|
|
119314
119533
|
try {
|
|
119315
|
-
await ensureDir(
|
|
119534
|
+
await ensureDir(dirname6(this.filePath));
|
|
119316
119535
|
await writeFile8(this.filePath, JSON.stringify(state, null, 2), "utf-8");
|
|
119317
119536
|
} catch {
|
|
119318
119537
|
}
|
|
@@ -119868,8 +120087,8 @@ if (!envLoaded && !process.env.DATABASE_URL) {
|
|
|
119868
120087
|
process.env.SKIP_ENV_VALIDATION = "1";
|
|
119869
120088
|
}
|
|
119870
120089
|
var runtimeTarget = `bun-${process.platform}-${process.arch}`;
|
|
119871
|
-
var buildVersion = "0.
|
|
119872
|
-
var buildCommit = "
|
|
120090
|
+
var buildVersion = "0.16.1".length > 0 ? "0.16.1" : "0.0.0-dev";
|
|
120091
|
+
var buildCommit = "7f0ef62".length > 0 ? "7f0ef62" : "dev";
|
|
119873
120092
|
var buildTarget = "node".length > 0 ? "node" : runtimeTarget;
|
|
119874
120093
|
var isDevBuild = buildVersion.includes("dev") || buildCommit === "dev";
|
|
119875
120094
|
var versionLabel = `skill v${buildVersion} (${buildCommit}) ${buildTarget}`;
|
|
@@ -120088,6 +120307,7 @@ registerDeployCommands(program2);
|
|
|
120088
120307
|
registerKbCommands(program2);
|
|
120089
120308
|
registerAuthCommands(program2, usageState);
|
|
120090
120309
|
registerConfigCommands(program2);
|
|
120310
|
+
registerKeysCommands(program2);
|
|
120091
120311
|
registerPluginSyncCommand(program2);
|
|
120092
120312
|
program2.command("mcp").description(
|
|
120093
120313
|
"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)"
|