@skillrecordings/cli 0.16.1 → 0.18.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/chunk-7SQU7KCI.js +223 -0
- package/dist/chunk-7SQU7KCI.js.map +1 -0
- package/dist/{chunk-L6YTBYNV.js → chunk-IR6KG25Y.js} +6 -6
- package/dist/{chunk-A5RBWKVF.js → chunk-J4IC3GC3.js} +5 -5
- package/dist/{config-44V5DJBS.js → config-C7CDVTO7.js} +4 -4
- package/dist/index.js +1043 -299
- package/dist/index.js.map +1 -1
- package/dist/keychain-IEZHT5WN.js +30 -0
- package/dist/{pipeline-FGI6ICWM.js → pipeline-TMFQSA7X.js} +4 -4
- package/dist/pipeline-TMFQSA7X.js.map +1 -0
- package/package.json +1 -1
- /package/dist/{chunk-L6YTBYNV.js.map → chunk-IR6KG25Y.js.map} +0 -0
- /package/dist/{chunk-A5RBWKVF.js.map → chunk-J4IC3GC3.js.map} +0 -0
- /package/dist/{config-44V5DJBS.js.map → config-C7CDVTO7.js.map} +0 -0
- /package/dist/{pipeline-FGI6ICWM.js.map → keychain-IEZHT5WN.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -20,8 +20,9 @@ import {
|
|
|
20
20
|
runPipeline,
|
|
21
21
|
validate,
|
|
22
22
|
validateSync
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-J4IC3GC3.js";
|
|
24
24
|
import "./chunk-HK3PEWFD.js";
|
|
25
|
+
import "./chunk-WYKL32C3.js";
|
|
25
26
|
import {
|
|
26
27
|
createFilterStats,
|
|
27
28
|
formatFilterStats,
|
|
@@ -39,20 +40,28 @@ import {
|
|
|
39
40
|
getApp,
|
|
40
41
|
getOutcomeHistory,
|
|
41
42
|
getRedis
|
|
42
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-IR6KG25Y.js";
|
|
43
44
|
import "./chunk-KEV3QKXP.js";
|
|
44
|
-
import "./chunk-ZNF7XD2S.js";
|
|
45
|
-
import {
|
|
46
|
-
upsertVector
|
|
47
|
-
} from "./chunk-H3D6VCME.js";
|
|
48
|
-
import "./chunk-F4EM72IH.js";
|
|
49
|
-
import "./chunk-WYKL32C3.js";
|
|
50
45
|
import {
|
|
51
46
|
MemoryService,
|
|
52
47
|
VotingService,
|
|
53
48
|
calculateConfidence
|
|
54
49
|
} from "./chunk-MLNDSBZ4.js";
|
|
50
|
+
import "./chunk-ZNF7XD2S.js";
|
|
51
|
+
import {
|
|
52
|
+
upsertVector
|
|
53
|
+
} from "./chunk-H3D6VCME.js";
|
|
55
54
|
import "./chunk-MG37YDAK.js";
|
|
55
|
+
import "./chunk-F4EM72IH.js";
|
|
56
|
+
import {
|
|
57
|
+
addShellIntegration,
|
|
58
|
+
autoBootstrapKeychain,
|
|
59
|
+
getFromKeychain,
|
|
60
|
+
getKeychainStatus,
|
|
61
|
+
isKeychainSupported,
|
|
62
|
+
isOpCliAvailable,
|
|
63
|
+
storeInKeychain
|
|
64
|
+
} from "./chunk-7SQU7KCI.js";
|
|
56
65
|
import {
|
|
57
66
|
OnePasswordProvider,
|
|
58
67
|
SECRET_REFS,
|
|
@@ -74611,9 +74620,9 @@ function parseEnvContent(content) {
|
|
|
74611
74620
|
return env;
|
|
74612
74621
|
}
|
|
74613
74622
|
async function decryptEnvFile(encryptedPath) {
|
|
74614
|
-
const { existsSync:
|
|
74623
|
+
const { existsSync: existsSync17 } = await import("fs");
|
|
74615
74624
|
const { readFile: readFile10 } = await import("fs/promises");
|
|
74616
|
-
if (!
|
|
74625
|
+
if (!existsSync17(encryptedPath)) {
|
|
74617
74626
|
return {};
|
|
74618
74627
|
}
|
|
74619
74628
|
const ageKey = await getAgeKeyFrom1Password();
|
|
@@ -74630,19 +74639,43 @@ async function decryptEnvFile(encryptedPath) {
|
|
|
74630
74639
|
}
|
|
74631
74640
|
}
|
|
74632
74641
|
async function getAgeKeyFrom1Password() {
|
|
74633
|
-
if (
|
|
74634
|
-
return
|
|
74642
|
+
if (process.env.SKILL_AGE_KEY) {
|
|
74643
|
+
return process.env.SKILL_AGE_KEY;
|
|
74635
74644
|
}
|
|
74636
74645
|
try {
|
|
74637
|
-
const {
|
|
74638
|
-
const
|
|
74639
|
-
if (
|
|
74640
|
-
|
|
74646
|
+
const { getFromKeychain: getFromKeychain2, storeInKeychain: storeInKeychain2, autoBootstrapKeychain: autoBootstrapKeychain2 } = await import("./keychain-IEZHT5WN.js");
|
|
74647
|
+
const fromKeychain = getFromKeychain2("age-private-key");
|
|
74648
|
+
if (fromKeychain) return fromKeychain;
|
|
74649
|
+
let opToken = process.env.OP_SERVICE_ACCOUNT_TOKEN;
|
|
74650
|
+
if (!opToken) {
|
|
74651
|
+
opToken = autoBootstrapKeychain2() ?? void 0;
|
|
74652
|
+
}
|
|
74653
|
+
if (opToken) {
|
|
74654
|
+
const originalEnv = process.env.OP_SERVICE_ACCOUNT_TOKEN;
|
|
74655
|
+
process.env.OP_SERVICE_ACCOUNT_TOKEN = opToken;
|
|
74656
|
+
try {
|
|
74657
|
+
const { OnePasswordProvider: OnePasswordProvider2 } = await import("./secrets-MGVPGMFJ.js");
|
|
74658
|
+
const op = new OnePasswordProvider2();
|
|
74659
|
+
if (await op.isAvailable()) {
|
|
74660
|
+
const key = await op.resolve(
|
|
74661
|
+
"op://Support/skill-cli-age-key/private_key"
|
|
74662
|
+
);
|
|
74663
|
+
if (key) {
|
|
74664
|
+
storeInKeychain2("age-private-key", key);
|
|
74665
|
+
return key;
|
|
74666
|
+
}
|
|
74667
|
+
}
|
|
74668
|
+
} finally {
|
|
74669
|
+
if (originalEnv) {
|
|
74670
|
+
process.env.OP_SERVICE_ACCOUNT_TOKEN = originalEnv;
|
|
74671
|
+
} else {
|
|
74672
|
+
delete process.env.OP_SERVICE_ACCOUNT_TOKEN;
|
|
74673
|
+
}
|
|
74674
|
+
}
|
|
74641
74675
|
}
|
|
74642
|
-
return await op.resolve("op://Support/skill-cli-age-key/private_key");
|
|
74643
74676
|
} catch {
|
|
74644
|
-
return null;
|
|
74645
74677
|
}
|
|
74678
|
+
return null;
|
|
74646
74679
|
}
|
|
74647
74680
|
async function loadShippedDefaults(cliRoot2) {
|
|
74648
74681
|
const encryptedPath = resolve(cliRoot2, ".env.encrypted");
|
|
@@ -74719,7 +74752,7 @@ var ROOT_DESCRIPTIONS = {
|
|
|
74719
74752
|
minimal: "Skill Recordings support agent CLI. Try: skill wizard, skill keys, skill front inbox, skill front triage. Use --help for details."
|
|
74720
74753
|
};
|
|
74721
74754
|
var FRONT_DESCRIPTIONS = {
|
|
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.",
|
|
74755
|
+
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.\n\n Environment: FRONT_API_TOKEN required. Run `skill doctor` to check.",
|
|
74723
74756
|
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
74757
|
minimal: "Front API commands (inbox, triage, assign, reply, archive)."
|
|
74725
74758
|
};
|
|
@@ -74729,7 +74762,7 @@ var AUTH_DESCRIPTIONS = {
|
|
|
74729
74762
|
minimal: "Auth status commands (auth status, auth whoami)."
|
|
74730
74763
|
};
|
|
74731
74764
|
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",
|
|
74765
|
+
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\n\n Environment: INNGEST_SIGNING_KEY required. Run `skill doctor` to check.",
|
|
74733
74766
|
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
74767
|
minimal: "Inngest events and runs debugging."
|
|
74735
74768
|
};
|
|
@@ -75667,6 +75700,74 @@ function registerAuthCommands(program3, usageState2) {
|
|
|
75667
75700
|
// src/commands/axiom/index.ts
|
|
75668
75701
|
init_esm_shims();
|
|
75669
75702
|
|
|
75703
|
+
// src/core/spinner.ts
|
|
75704
|
+
init_esm_shims();
|
|
75705
|
+
var FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
75706
|
+
var INTERVAL = 80;
|
|
75707
|
+
function createSpinner() {
|
|
75708
|
+
const isTTY = process.stderr.isTTY && !process.env.CI;
|
|
75709
|
+
let interval = null;
|
|
75710
|
+
let frameIndex = 0;
|
|
75711
|
+
let currentMessage = "";
|
|
75712
|
+
const clear = () => {
|
|
75713
|
+
if (!isTTY) return;
|
|
75714
|
+
process.stderr.write("\r\x1B[K");
|
|
75715
|
+
};
|
|
75716
|
+
const render3 = () => {
|
|
75717
|
+
if (!isTTY) return;
|
|
75718
|
+
const frame = FRAMES[frameIndex];
|
|
75719
|
+
process.stderr.write(`\r${frame} ${currentMessage}`);
|
|
75720
|
+
frameIndex = (frameIndex + 1) % FRAMES.length;
|
|
75721
|
+
};
|
|
75722
|
+
const start = (message = "Loading...") => {
|
|
75723
|
+
if (!isTTY) return;
|
|
75724
|
+
currentMessage = message;
|
|
75725
|
+
frameIndex = 0;
|
|
75726
|
+
render3();
|
|
75727
|
+
interval = setInterval(render3, INTERVAL);
|
|
75728
|
+
};
|
|
75729
|
+
const update2 = (message) => {
|
|
75730
|
+
currentMessage = message;
|
|
75731
|
+
if (isTTY && !interval) {
|
|
75732
|
+
render3();
|
|
75733
|
+
}
|
|
75734
|
+
};
|
|
75735
|
+
const stop = () => {
|
|
75736
|
+
if (interval) {
|
|
75737
|
+
clearInterval(interval);
|
|
75738
|
+
interval = null;
|
|
75739
|
+
}
|
|
75740
|
+
clear();
|
|
75741
|
+
};
|
|
75742
|
+
const succeed = (message) => {
|
|
75743
|
+
stop();
|
|
75744
|
+
if (isTTY && message) {
|
|
75745
|
+
process.stderr.write(`\u2713 ${message}
|
|
75746
|
+
`);
|
|
75747
|
+
}
|
|
75748
|
+
};
|
|
75749
|
+
const fail = (message) => {
|
|
75750
|
+
stop();
|
|
75751
|
+
if (isTTY && message) {
|
|
75752
|
+
process.stderr.write(`\u2717 ${message}
|
|
75753
|
+
`);
|
|
75754
|
+
}
|
|
75755
|
+
};
|
|
75756
|
+
return { start, update: update2, stop, succeed, fail };
|
|
75757
|
+
}
|
|
75758
|
+
async function withSpinner(message, fn) {
|
|
75759
|
+
const spinner = createSpinner();
|
|
75760
|
+
spinner.start(message);
|
|
75761
|
+
try {
|
|
75762
|
+
const result = await fn();
|
|
75763
|
+
spinner.stop();
|
|
75764
|
+
return result;
|
|
75765
|
+
} catch (error) {
|
|
75766
|
+
spinner.stop();
|
|
75767
|
+
throw error;
|
|
75768
|
+
}
|
|
75769
|
+
}
|
|
75770
|
+
|
|
75670
75771
|
// src/lib/axiom-client.ts
|
|
75671
75772
|
init_esm_shims();
|
|
75672
75773
|
import { Axiom } from "@axiomhq/js";
|
|
@@ -76365,10 +76466,13 @@ async function runQuery(ctx, apl, options) {
|
|
|
76365
76466
|
const { startTime, endTime } = parseTimeRange(options.since ?? "24h");
|
|
76366
76467
|
const outputJson = options.json === true || ctx.format === "json";
|
|
76367
76468
|
try {
|
|
76368
|
-
const result = await
|
|
76369
|
-
|
|
76370
|
-
|
|
76371
|
-
|
|
76469
|
+
const result = await withSpinner(
|
|
76470
|
+
"Running query...",
|
|
76471
|
+
() => client.query(apl, {
|
|
76472
|
+
startTime: startTime.toISOString(),
|
|
76473
|
+
endTime: endTime.toISOString()
|
|
76474
|
+
})
|
|
76475
|
+
);
|
|
76372
76476
|
if (outputJson) {
|
|
76373
76477
|
ctx.output.data(result);
|
|
76374
76478
|
return;
|
|
@@ -76412,10 +76516,13 @@ async function listAgentRuns(ctx, options) {
|
|
|
76412
76516
|
| sort by _time desc
|
|
76413
76517
|
| limit ${limit2}`;
|
|
76414
76518
|
try {
|
|
76415
|
-
const result = await
|
|
76416
|
-
|
|
76417
|
-
|
|
76418
|
-
|
|
76519
|
+
const result = await withSpinner(
|
|
76520
|
+
"Loading agent runs...",
|
|
76521
|
+
() => client.query(apl, {
|
|
76522
|
+
startTime: startTime.toISOString(),
|
|
76523
|
+
endTime: endTime.toISOString()
|
|
76524
|
+
})
|
|
76525
|
+
);
|
|
76419
76526
|
const matches = result.matches ?? [];
|
|
76420
76527
|
if (outputJson) {
|
|
76421
76528
|
ctx.output.data(matches.map((m) => m.data));
|
|
@@ -76469,10 +76576,13 @@ async function listErrors(ctx, options) {
|
|
|
76469
76576
|
| sort by _time desc
|
|
76470
76577
|
| limit ${limit2}`;
|
|
76471
76578
|
try {
|
|
76472
|
-
const result = await
|
|
76473
|
-
|
|
76474
|
-
|
|
76475
|
-
|
|
76579
|
+
const result = await withSpinner(
|
|
76580
|
+
"Loading errors...",
|
|
76581
|
+
() => client.query(apl, {
|
|
76582
|
+
startTime: startTime.toISOString(),
|
|
76583
|
+
endTime: endTime.toISOString()
|
|
76584
|
+
})
|
|
76585
|
+
);
|
|
76476
76586
|
const matches = result.matches ?? [];
|
|
76477
76587
|
if (outputJson) {
|
|
76478
76588
|
ctx.output.data(matches.map((m) => m.data));
|
|
@@ -76509,10 +76619,13 @@ async function getConversation(ctx, conversationId, options) {
|
|
|
76509
76619
|
| where conversationId == '${conversationId}'
|
|
76510
76620
|
| sort by _time asc`;
|
|
76511
76621
|
try {
|
|
76512
|
-
const result = await
|
|
76513
|
-
|
|
76514
|
-
|
|
76515
|
-
|
|
76622
|
+
const result = await withSpinner(
|
|
76623
|
+
"Loading conversation...",
|
|
76624
|
+
() => client.query(apl, {
|
|
76625
|
+
startTime: startTime.toISOString(),
|
|
76626
|
+
endTime: endTime.toISOString()
|
|
76627
|
+
})
|
|
76628
|
+
);
|
|
76516
76629
|
const matches = result.matches ?? [];
|
|
76517
76630
|
if (outputJson) {
|
|
76518
76631
|
ctx.output.data(
|
|
@@ -76568,10 +76681,13 @@ async function getClassificationStats(ctx, options) {
|
|
|
76568
76681
|
apl += `
|
|
76569
76682
|
| summarize count = count() by category, complexity`;
|
|
76570
76683
|
try {
|
|
76571
|
-
const result = await
|
|
76572
|
-
|
|
76573
|
-
|
|
76574
|
-
|
|
76684
|
+
const result = await withSpinner(
|
|
76685
|
+
"Loading classifications...",
|
|
76686
|
+
() => client.query(apl, {
|
|
76687
|
+
startTime: startTime.toISOString(),
|
|
76688
|
+
endTime: endTime.toISOString()
|
|
76689
|
+
})
|
|
76690
|
+
);
|
|
76575
76691
|
const buckets = result.buckets?.totals ?? [];
|
|
76576
76692
|
if (outputJson) {
|
|
76577
76693
|
ctx.output.data(buckets);
|
|
@@ -76631,10 +76747,13 @@ async function listWorkflowSteps(ctx, options) {
|
|
|
76631
76747
|
| sort by _time desc
|
|
76632
76748
|
| limit ${limit2}`;
|
|
76633
76749
|
try {
|
|
76634
|
-
const result = await
|
|
76635
|
-
|
|
76636
|
-
|
|
76637
|
-
|
|
76750
|
+
const result = await withSpinner(
|
|
76751
|
+
"Loading workflow steps...",
|
|
76752
|
+
() => client.query(apl, {
|
|
76753
|
+
startTime: startTime.toISOString(),
|
|
76754
|
+
endTime: endTime.toISOString()
|
|
76755
|
+
})
|
|
76756
|
+
);
|
|
76638
76757
|
const matches = result.matches ?? [];
|
|
76639
76758
|
if (outputJson) {
|
|
76640
76759
|
ctx.output.data(matches.map((m) => m.data));
|
|
@@ -76677,10 +76796,13 @@ async function listApprovals(ctx, options) {
|
|
|
76677
76796
|
| sort by _time desc
|
|
76678
76797
|
| limit ${limit2}`;
|
|
76679
76798
|
try {
|
|
76680
|
-
const result = await
|
|
76681
|
-
|
|
76682
|
-
|
|
76683
|
-
|
|
76799
|
+
const result = await withSpinner(
|
|
76800
|
+
"Loading approvals...",
|
|
76801
|
+
() => client.query(apl, {
|
|
76802
|
+
startTime: startTime.toISOString(),
|
|
76803
|
+
endTime: endTime.toISOString()
|
|
76804
|
+
})
|
|
76805
|
+
);
|
|
76684
76806
|
const matches = result.matches ?? [];
|
|
76685
76807
|
if (outputJson) {
|
|
76686
76808
|
ctx.output.data(matches.map((m) => m.data));
|
|
@@ -76716,7 +76838,9 @@ async function listApprovals(ctx, options) {
|
|
|
76716
76838
|
}
|
|
76717
76839
|
}
|
|
76718
76840
|
function registerAxiomCommands(program3) {
|
|
76719
|
-
const axiom = program3.command("axiom").description(
|
|
76841
|
+
const axiom = program3.command("axiom").description(
|
|
76842
|
+
"Query Axiom logs and traces.\n Environment: AXIOM_TOKEN required. Run `skill doctor` to check."
|
|
76843
|
+
);
|
|
76720
76844
|
axiom.command("query").description("Run a raw APL query").argument("<apl>", "APL query string").option("-s, --since <time>", "Time range (e.g., 1h, 24h, 7d)", "24h").option("--json", "Output as JSON").action(async (apl, options, command) => {
|
|
76721
76845
|
const opts = typeof command.optsWithGlobals === "function" ? command.optsWithGlobals() : {
|
|
76722
76846
|
...command.parent?.opts(),
|
|
@@ -76954,11 +77078,11 @@ Saved to ${options.output}`);
|
|
|
76954
77078
|
}
|
|
76955
77079
|
}
|
|
76956
77080
|
async function toEvalite(options) {
|
|
76957
|
-
const { readFileSync:
|
|
77081
|
+
const { readFileSync: readFileSync14 } = await import("fs");
|
|
76958
77082
|
const { ctx } = options;
|
|
76959
77083
|
const outputJson = ctx.format === "json";
|
|
76960
77084
|
const data2 = JSON.parse(
|
|
76961
|
-
|
|
77085
|
+
readFileSync14(options.input, "utf-8")
|
|
76962
77086
|
);
|
|
76963
77087
|
const evaliteData = data2.map((d) => ({
|
|
76964
77088
|
input: d.triggerMessage.body,
|
|
@@ -77762,6 +77886,170 @@ function registerDeployCommands(program3) {
|
|
|
77762
77886
|
});
|
|
77763
77887
|
}
|
|
77764
77888
|
|
|
77889
|
+
// src/commands/doctor.ts
|
|
77890
|
+
init_esm_shims();
|
|
77891
|
+
import { execSync as execSync3 } from "child_process";
|
|
77892
|
+
import { existsSync as existsSync6 } from "fs";
|
|
77893
|
+
import { join as join3 } from "path";
|
|
77894
|
+
var REQUIRED_ENV_VARS = [
|
|
77895
|
+
"DATABASE_URL",
|
|
77896
|
+
"INNGEST_SIGNING_KEY",
|
|
77897
|
+
"INNGEST_EVENT_KEY",
|
|
77898
|
+
"FRONT_API_TOKEN",
|
|
77899
|
+
"LINEAR_API_KEY",
|
|
77900
|
+
"AXIOM_TOKEN",
|
|
77901
|
+
"SLACK_BOT_TOKEN",
|
|
77902
|
+
"UPSTASH_REDIS_REST_URL",
|
|
77903
|
+
"UPSTASH_VECTOR_REST_URL"
|
|
77904
|
+
];
|
|
77905
|
+
function checkEnvVars() {
|
|
77906
|
+
return REQUIRED_ENV_VARS.map((varName) => {
|
|
77907
|
+
const value = process.env[varName];
|
|
77908
|
+
return {
|
|
77909
|
+
name: varName,
|
|
77910
|
+
status: value ? "ok" : "warn",
|
|
77911
|
+
message: value ? void 0 : "Not set"
|
|
77912
|
+
};
|
|
77913
|
+
});
|
|
77914
|
+
}
|
|
77915
|
+
function checkKeychain() {
|
|
77916
|
+
const checks = [];
|
|
77917
|
+
const opAvailable = isOpCliAvailable();
|
|
77918
|
+
checks.push({
|
|
77919
|
+
name: "op CLI",
|
|
77920
|
+
status: opAvailable ? "ok" : "warn",
|
|
77921
|
+
message: opAvailable ? void 0 : "Not installed or not authenticated"
|
|
77922
|
+
});
|
|
77923
|
+
const opToken = getFromKeychain("op-service-account-token");
|
|
77924
|
+
checks.push({
|
|
77925
|
+
name: "op-service-account-token",
|
|
77926
|
+
status: opToken ? "ok" : "warn",
|
|
77927
|
+
message: opToken ? void 0 : "Not found in keychain"
|
|
77928
|
+
});
|
|
77929
|
+
const ageKey = getFromKeychain("age-private-key");
|
|
77930
|
+
checks.push({
|
|
77931
|
+
name: "age-private-key",
|
|
77932
|
+
status: ageKey ? "ok" : "warn",
|
|
77933
|
+
message: ageKey ? void 0 : "Not found in keychain"
|
|
77934
|
+
});
|
|
77935
|
+
return checks;
|
|
77936
|
+
}
|
|
77937
|
+
function checkTools() {
|
|
77938
|
+
const checks = [];
|
|
77939
|
+
try {
|
|
77940
|
+
execSync3("gh auth status", { stdio: "pipe", timeout: 3e3 });
|
|
77941
|
+
checks.push({
|
|
77942
|
+
name: "gh CLI",
|
|
77943
|
+
status: "ok"
|
|
77944
|
+
});
|
|
77945
|
+
} catch {
|
|
77946
|
+
checks.push({
|
|
77947
|
+
name: "gh CLI",
|
|
77948
|
+
status: "warn",
|
|
77949
|
+
message: "Not installed or not authenticated"
|
|
77950
|
+
});
|
|
77951
|
+
}
|
|
77952
|
+
return checks;
|
|
77953
|
+
}
|
|
77954
|
+
function checkWorkspace() {
|
|
77955
|
+
const checks = [];
|
|
77956
|
+
const hivePath = join3(process.cwd(), ".hive");
|
|
77957
|
+
const hiveExists = existsSync6(hivePath);
|
|
77958
|
+
checks.push({
|
|
77959
|
+
name: ".hive directory",
|
|
77960
|
+
status: hiveExists ? "ok" : "warn",
|
|
77961
|
+
message: hiveExists ? void 0 : "Not found in current directory"
|
|
77962
|
+
});
|
|
77963
|
+
return checks;
|
|
77964
|
+
}
|
|
77965
|
+
function runHealthChecks() {
|
|
77966
|
+
const categories = [
|
|
77967
|
+
{
|
|
77968
|
+
category: "Environment",
|
|
77969
|
+
checks: checkEnvVars()
|
|
77970
|
+
},
|
|
77971
|
+
{
|
|
77972
|
+
category: "Keychain",
|
|
77973
|
+
checks: checkKeychain()
|
|
77974
|
+
},
|
|
77975
|
+
{
|
|
77976
|
+
category: "Tools",
|
|
77977
|
+
checks: checkTools()
|
|
77978
|
+
},
|
|
77979
|
+
{
|
|
77980
|
+
category: "Workspace",
|
|
77981
|
+
checks: checkWorkspace()
|
|
77982
|
+
}
|
|
77983
|
+
];
|
|
77984
|
+
let total = 0;
|
|
77985
|
+
let ok = 0;
|
|
77986
|
+
let warn = 0;
|
|
77987
|
+
let fail = 0;
|
|
77988
|
+
for (const category of categories) {
|
|
77989
|
+
for (const check of category.checks) {
|
|
77990
|
+
total++;
|
|
77991
|
+
if (check.status === "ok") ok++;
|
|
77992
|
+
else if (check.status === "warn") warn++;
|
|
77993
|
+
else fail++;
|
|
77994
|
+
}
|
|
77995
|
+
}
|
|
77996
|
+
let status;
|
|
77997
|
+
if (fail > 0) {
|
|
77998
|
+
status = "unhealthy";
|
|
77999
|
+
} else if (warn > 3) {
|
|
78000
|
+
status = "degraded";
|
|
78001
|
+
} else {
|
|
78002
|
+
status = "healthy";
|
|
78003
|
+
}
|
|
78004
|
+
return {
|
|
78005
|
+
status,
|
|
78006
|
+
categories,
|
|
78007
|
+
summary: { total, ok, warn, fail }
|
|
78008
|
+
};
|
|
78009
|
+
}
|
|
78010
|
+
function formatTextOutput(results) {
|
|
78011
|
+
console.log("\n\u{1FA7A} Health Check Results\n");
|
|
78012
|
+
for (const category of results.categories) {
|
|
78013
|
+
console.log(`${category.category}:`);
|
|
78014
|
+
for (const check of category.checks) {
|
|
78015
|
+
const symbol = check.status === "ok" ? "\u2713" : check.status === "warn" ? "\u26A0" : "\u2717";
|
|
78016
|
+
const line = check.message ? ` ${symbol} ${check.name} - ${check.message}` : ` ${symbol} ${check.name}`;
|
|
78017
|
+
console.log(line);
|
|
78018
|
+
}
|
|
78019
|
+
console.log("");
|
|
78020
|
+
}
|
|
78021
|
+
console.log("\u2500".repeat(60));
|
|
78022
|
+
console.log(
|
|
78023
|
+
`Summary: ${results.summary.ok}/${results.summary.total} checks passed`
|
|
78024
|
+
);
|
|
78025
|
+
if (results.summary.warn > 0) {
|
|
78026
|
+
console.log(`\u26A0 ${results.summary.warn} warnings`);
|
|
78027
|
+
}
|
|
78028
|
+
if (results.summary.fail > 0) {
|
|
78029
|
+
console.log(`\u2717 ${results.summary.fail} failures`);
|
|
78030
|
+
}
|
|
78031
|
+
console.log(`
|
|
78032
|
+
Overall status: ${results.status.toUpperCase()}`);
|
|
78033
|
+
console.log("");
|
|
78034
|
+
}
|
|
78035
|
+
function registerDoctorCommand(program3) {
|
|
78036
|
+
program3.command("doctor").description(
|
|
78037
|
+
"Run health checks on environment and tools\n\n Checks:\n - Environment variables\n - Keychain secrets\n - CLI tools (gh, op)\n - Workspace setup (.hive)\n\n Examples:\n skill doctor\n skill doctor --json"
|
|
78038
|
+
).option("--json", "Output as JSON").action(async (options, command) => {
|
|
78039
|
+
const ctx = await createContext({
|
|
78040
|
+
format: options.json ? "json" : "text",
|
|
78041
|
+
verbose: command.optsWithGlobals().verbose,
|
|
78042
|
+
quiet: command.optsWithGlobals().quiet
|
|
78043
|
+
});
|
|
78044
|
+
const results = runHealthChecks();
|
|
78045
|
+
if (options.json || ctx.format === "json") {
|
|
78046
|
+
ctx.output.data(results);
|
|
78047
|
+
} else {
|
|
78048
|
+
formatTextOutput(results);
|
|
78049
|
+
}
|
|
78050
|
+
});
|
|
78051
|
+
}
|
|
78052
|
+
|
|
77765
78053
|
// src/commands/eval.ts
|
|
77766
78054
|
init_esm_shims();
|
|
77767
78055
|
import { access, readFile as readFile2 } from "fs/promises";
|
|
@@ -79769,12 +80057,12 @@ async function scoreProduction(ctx, options) {
|
|
|
79769
80057
|
|
|
79770
80058
|
// src/commands/eval-local/seed.ts
|
|
79771
80059
|
init_esm_shims();
|
|
79772
|
-
import { join as
|
|
80060
|
+
import { join as join5 } from "path";
|
|
79773
80061
|
import { glob as glob3 } from "glob";
|
|
79774
80062
|
|
|
79775
80063
|
// src/lib/eval-seed.ts
|
|
79776
80064
|
init_esm_shims();
|
|
79777
|
-
import { join as
|
|
80065
|
+
import { join as join4 } from "path";
|
|
79778
80066
|
import { readFile as readFile5, readdir } from "fs/promises";
|
|
79779
80067
|
import { glob as glob2 } from "glob";
|
|
79780
80068
|
import matter from "gray-matter";
|
|
@@ -79820,7 +80108,7 @@ async function loadJsonFiles(dirPath) {
|
|
|
79820
80108
|
const jsonFiles = files.filter((f) => f.endsWith(".json"));
|
|
79821
80109
|
const items = await Promise.all(
|
|
79822
80110
|
jsonFiles.map(async (file) => {
|
|
79823
|
-
const content = await readFile5(
|
|
80111
|
+
const content = await readFile5(join4(dirPath, file), "utf-8");
|
|
79824
80112
|
return JSON.parse(content);
|
|
79825
80113
|
})
|
|
79826
80114
|
);
|
|
@@ -79830,7 +80118,7 @@ async function loadJsonFiles(dirPath) {
|
|
|
79830
80118
|
}
|
|
79831
80119
|
}
|
|
79832
80120
|
async function loadKnowledgeFiles(basePath) {
|
|
79833
|
-
const files = await glob2(
|
|
80121
|
+
const files = await glob2(join4(basePath, "**/*.md"));
|
|
79834
80122
|
const docs = [];
|
|
79835
80123
|
for (const filePath of files) {
|
|
79836
80124
|
const content = await readFile5(filePath, "utf-8");
|
|
@@ -80020,16 +80308,16 @@ async function seed(ctx, options) {
|
|
|
80020
80308
|
await cleanQdrant();
|
|
80021
80309
|
}
|
|
80022
80310
|
log("\u{1F4E6} Seeding apps...");
|
|
80023
|
-
const apps = await loadJsonFiles(
|
|
80311
|
+
const apps = await loadJsonFiles(join5(fixturesPath, "apps"));
|
|
80024
80312
|
result.apps = await seedApps(connection, apps);
|
|
80025
80313
|
log("\u{1F465} Loading customer fixtures...");
|
|
80026
|
-
const customers = await loadJsonFiles(
|
|
80314
|
+
const customers = await loadJsonFiles(join5(fixturesPath, "customers"));
|
|
80027
80315
|
result.customers = customers.length;
|
|
80028
80316
|
log("\u{1F4DA} Seeding knowledge base...");
|
|
80029
|
-
const knowledge = await loadKnowledgeFiles(
|
|
80317
|
+
const knowledge = await loadKnowledgeFiles(join5(fixturesPath, "knowledge"));
|
|
80030
80318
|
result.knowledge = knowledge.length;
|
|
80031
80319
|
result.embeddings = await seedKnowledgeBase(knowledge, !outputJson);
|
|
80032
|
-
const scenarioFiles = await glob3(
|
|
80320
|
+
const scenarioFiles = await glob3(join5(fixturesPath, "scenarios/**/*.json"));
|
|
80033
80321
|
result.scenarios = scenarioFiles.length;
|
|
80034
80322
|
await connection.end();
|
|
80035
80323
|
if (outputJson) {
|
|
@@ -80105,8 +80393,8 @@ init_esm_shims();
|
|
|
80105
80393
|
// src/commands/eval-pipeline/run.ts
|
|
80106
80394
|
init_esm_shims();
|
|
80107
80395
|
import { createHash as createHash2 } from "crypto";
|
|
80108
|
-
import { existsSync as
|
|
80109
|
-
import { join as
|
|
80396
|
+
import { existsSync as existsSync7, mkdirSync, readFileSync as readFileSync5, rmSync, writeFileSync as writeFileSync4 } from "fs";
|
|
80397
|
+
import { join as join6 } from "path";
|
|
80110
80398
|
import { readFile as readFile6 } from "fs/promises";
|
|
80111
80399
|
import { glob as glob4 } from "glob";
|
|
80112
80400
|
|
|
@@ -80519,11 +80807,11 @@ function getCacheKey(scenarioId, classifySourceHash) {
|
|
|
80519
80807
|
function getClassifySourceHash() {
|
|
80520
80808
|
try {
|
|
80521
80809
|
const possiblePaths = [
|
|
80522
|
-
|
|
80523
|
-
|
|
80810
|
+
join6(process.cwd(), "packages/core/src/pipeline/classify.ts"),
|
|
80811
|
+
join6(process.cwd(), "../core/src/pipeline/classify.ts")
|
|
80524
80812
|
];
|
|
80525
80813
|
for (const path of possiblePaths) {
|
|
80526
|
-
if (
|
|
80814
|
+
if (existsSync7(path)) {
|
|
80527
80815
|
const content = readFileSync5(path, "utf-8");
|
|
80528
80816
|
return createHash2("md5").update(content).digest("hex");
|
|
80529
80817
|
}
|
|
@@ -80533,9 +80821,9 @@ function getClassifySourceHash() {
|
|
|
80533
80821
|
return createHash2("md5").update(Math.floor(Date.now() / 3e5).toString()).digest("hex");
|
|
80534
80822
|
}
|
|
80535
80823
|
function loadCachedClassify(cacheKey) {
|
|
80536
|
-
const cachePath =
|
|
80824
|
+
const cachePath = join6(CACHE_DIR, `${cacheKey}.json`);
|
|
80537
80825
|
try {
|
|
80538
|
-
if (
|
|
80826
|
+
if (existsSync7(cachePath)) {
|
|
80539
80827
|
return JSON.parse(readFileSync5(cachePath, "utf-8"));
|
|
80540
80828
|
}
|
|
80541
80829
|
} catch {
|
|
@@ -80544,17 +80832,17 @@ function loadCachedClassify(cacheKey) {
|
|
|
80544
80832
|
}
|
|
80545
80833
|
function saveCachedClassify(cacheKey, result) {
|
|
80546
80834
|
try {
|
|
80547
|
-
if (!
|
|
80835
|
+
if (!existsSync7(CACHE_DIR)) {
|
|
80548
80836
|
mkdirSync(CACHE_DIR, { recursive: true });
|
|
80549
80837
|
}
|
|
80550
|
-
const cachePath =
|
|
80838
|
+
const cachePath = join6(CACHE_DIR, `${cacheKey}.json`);
|
|
80551
80839
|
writeFileSync4(cachePath, JSON.stringify(result));
|
|
80552
80840
|
} catch {
|
|
80553
80841
|
}
|
|
80554
80842
|
}
|
|
80555
80843
|
function clearClassifyCache() {
|
|
80556
80844
|
try {
|
|
80557
|
-
if (
|
|
80845
|
+
if (existsSync7(CACHE_DIR)) {
|
|
80558
80846
|
rmSync(CACHE_DIR, { recursive: true, force: true });
|
|
80559
80847
|
}
|
|
80560
80848
|
} catch {
|
|
@@ -81226,7 +81514,7 @@ async function runValidateEval(ctx, scenarios, options) {
|
|
|
81226
81514
|
return results;
|
|
81227
81515
|
}
|
|
81228
81516
|
async function runE2EEval(ctx, scenarios, options) {
|
|
81229
|
-
const { runPipeline: runPipeline2 } = await import("./pipeline-
|
|
81517
|
+
const { runPipeline: runPipeline2 } = await import("./pipeline-TMFQSA7X.js");
|
|
81230
81518
|
const concurrency = options.parallel || 1;
|
|
81231
81519
|
let completed = 0;
|
|
81232
81520
|
const outputJson = options.outputJson ?? false;
|
|
@@ -81430,7 +81718,7 @@ Latency: ${avgLatency.toFixed(0)}ms avg`);
|
|
|
81430
81718
|
|
|
81431
81719
|
// src/commands/eval-pipeline/seed.ts
|
|
81432
81720
|
init_esm_shims();
|
|
81433
|
-
import { join as
|
|
81721
|
+
import { join as join7 } from "path";
|
|
81434
81722
|
import { glob as glob5 } from "glob";
|
|
81435
81723
|
async function seed2(ctx, options) {
|
|
81436
81724
|
const fixturesPath = options.fixtures || "fixtures";
|
|
@@ -81461,20 +81749,20 @@ async function seed2(ctx, options) {
|
|
|
81461
81749
|
await cleanQdrant();
|
|
81462
81750
|
}
|
|
81463
81751
|
if (!outputJson) ctx.output.message("\u{1F4E6} Seeding apps...");
|
|
81464
|
-
const apps = await loadJsonFiles(
|
|
81752
|
+
const apps = await loadJsonFiles(join7(fixturesPath, "apps"));
|
|
81465
81753
|
result.apps = await seedApps(connection, apps);
|
|
81466
81754
|
const [trustRows] = await connection.execute(
|
|
81467
81755
|
"SELECT COUNT(*) as count FROM SUPPORT_trust_scores"
|
|
81468
81756
|
);
|
|
81469
81757
|
result.trustScores = trustRows[0].count;
|
|
81470
81758
|
if (!outputJson) ctx.output.message("\u{1F465} Loading customer fixtures...");
|
|
81471
|
-
const customers = await loadJsonFiles(
|
|
81759
|
+
const customers = await loadJsonFiles(join7(fixturesPath, "customers"));
|
|
81472
81760
|
result.customers = customers.length;
|
|
81473
81761
|
if (!outputJson) ctx.output.message("\u{1F4DA} Seeding knowledge base...");
|
|
81474
|
-
const knowledge = await loadKnowledgeFiles(
|
|
81762
|
+
const knowledge = await loadKnowledgeFiles(join7(fixturesPath, "knowledge"));
|
|
81475
81763
|
result.knowledge = knowledge.length;
|
|
81476
81764
|
result.embeddings = await seedKnowledgeBase(knowledge, !outputJson);
|
|
81477
|
-
const scenarioFiles = await glob5(
|
|
81765
|
+
const scenarioFiles = await glob5(join7(fixturesPath, "scenarios/**/*.json"));
|
|
81478
81766
|
result.scenarios = scenarioFiles.length;
|
|
81479
81767
|
await connection.end();
|
|
81480
81768
|
if (outputJson) {
|
|
@@ -81546,7 +81834,7 @@ function registerEvalPipelineCommands(program3) {
|
|
|
81546
81834
|
|
|
81547
81835
|
// src/commands/eval-prompt.ts
|
|
81548
81836
|
init_esm_shims();
|
|
81549
|
-
import { existsSync as
|
|
81837
|
+
import { existsSync as existsSync8, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
|
|
81550
81838
|
import { generateText as generateText2, stepCountIs as stepCountIs2, tool as tool4 } from "ai";
|
|
81551
81839
|
import { z as z5 } from "zod";
|
|
81552
81840
|
var leakPatterns = [
|
|
@@ -81733,7 +82021,7 @@ async function runEval2(ctx, options) {
|
|
|
81733
82021
|
try {
|
|
81734
82022
|
let prompt = SUPPORT_AGENT_PROMPT;
|
|
81735
82023
|
if (promptPath) {
|
|
81736
|
-
if (!
|
|
82024
|
+
if (!existsSync8(promptPath)) {
|
|
81737
82025
|
throw new CLIError({
|
|
81738
82026
|
userMessage: `Prompt file not found: ${promptPath}.`,
|
|
81739
82027
|
suggestion: "Verify the prompt path and try again."
|
|
@@ -81746,7 +82034,7 @@ async function runEval2(ctx, options) {
|
|
|
81746
82034
|
} else if (!outputJson) {
|
|
81747
82035
|
ctx.output.message("Using production prompt");
|
|
81748
82036
|
}
|
|
81749
|
-
if (!
|
|
82037
|
+
if (!existsSync8(datasetPath)) {
|
|
81750
82038
|
throw new CLIError({
|
|
81751
82039
|
userMessage: `Dataset not found: ${datasetPath}.`,
|
|
81752
82040
|
suggestion: "Provide a valid dataset file path."
|
|
@@ -81858,7 +82146,7 @@ async function comparePrompts(ctx, options) {
|
|
|
81858
82146
|
try {
|
|
81859
82147
|
const baselinePrompt = baseline ? readFileSync6(baseline, "utf-8") : SUPPORT_AGENT_PROMPT;
|
|
81860
82148
|
const candidatePrompt = readFileSync6(candidate, "utf-8");
|
|
81861
|
-
if (!
|
|
82149
|
+
if (!existsSync8(datasetPath)) {
|
|
81862
82150
|
throw new CLIError({
|
|
81863
82151
|
userMessage: `Dataset not found: ${datasetPath}.`,
|
|
81864
82152
|
suggestion: "Provide a valid dataset file path."
|
|
@@ -82006,20 +82294,20 @@ init_esm_shims();
|
|
|
82006
82294
|
|
|
82007
82295
|
// src/commands/faq/classify.ts
|
|
82008
82296
|
init_esm_shims();
|
|
82009
|
-
import { appendFileSync, existsSync as
|
|
82010
|
-
import { dirname as dirname2, join as
|
|
82297
|
+
import { appendFileSync, existsSync as existsSync9, mkdirSync as mkdirSync2, readFileSync as readFileSync7 } from "fs";
|
|
82298
|
+
import { dirname as dirname2, join as join8, resolve as resolve3 } from "path";
|
|
82011
82299
|
import { generateObject } from "ai";
|
|
82012
82300
|
import { z as z6 } from "zod";
|
|
82013
82301
|
var PROJECT_ROOT = resolve3(__dirname, "../../../..");
|
|
82014
|
-
var DEFAULT_PARQUET_PATH =
|
|
82302
|
+
var DEFAULT_PARQUET_PATH = join8(
|
|
82015
82303
|
PROJECT_ROOT,
|
|
82016
82304
|
"artifacts/phase-0/embeddings/v2/conversations.parquet"
|
|
82017
82305
|
);
|
|
82018
|
-
var DEFAULT_TAXONOMY_PATH =
|
|
82306
|
+
var DEFAULT_TAXONOMY_PATH = join8(
|
|
82019
82307
|
PROJECT_ROOT,
|
|
82020
82308
|
"artifacts/phase-1/llm-topics/taxonomy.json"
|
|
82021
82309
|
);
|
|
82022
|
-
var DEFAULT_OUTPUT_PATH =
|
|
82310
|
+
var DEFAULT_OUTPUT_PATH = join8(
|
|
82023
82311
|
PROJECT_ROOT,
|
|
82024
82312
|
"artifacts/phase-1/llm-topics/classifications.jsonl"
|
|
82025
82313
|
);
|
|
@@ -82053,7 +82341,7 @@ function createProgressReporter(ctx, total) {
|
|
|
82053
82341
|
};
|
|
82054
82342
|
}
|
|
82055
82343
|
async function loadConversationsFromParquet(parquetPath) {
|
|
82056
|
-
const { execSync:
|
|
82344
|
+
const { execSync: execSync4 } = await import("child_process");
|
|
82057
82345
|
const query = `
|
|
82058
82346
|
SELECT
|
|
82059
82347
|
conversation_id,
|
|
@@ -82064,7 +82352,7 @@ async function loadConversationsFromParquet(parquetPath) {
|
|
|
82064
82352
|
WHERE first_message IS NOT NULL
|
|
82065
82353
|
ORDER BY conversation_id
|
|
82066
82354
|
`;
|
|
82067
|
-
const result =
|
|
82355
|
+
const result = execSync4(`duckdb -json -c "${query.replace(/"/g, '\\"')}"`, {
|
|
82068
82356
|
encoding: "utf-8",
|
|
82069
82357
|
maxBuffer: 100 * 1024 * 1024
|
|
82070
82358
|
// 100MB buffer for large datasets
|
|
@@ -82074,7 +82362,7 @@ async function loadConversationsFromParquet(parquetPath) {
|
|
|
82074
82362
|
}
|
|
82075
82363
|
function loadExistingClassifications(outputPath) {
|
|
82076
82364
|
const classifiedIds = /* @__PURE__ */ new Set();
|
|
82077
|
-
if (!
|
|
82365
|
+
if (!existsSync9(outputPath)) {
|
|
82078
82366
|
return classifiedIds;
|
|
82079
82367
|
}
|
|
82080
82368
|
const content = readFileSync7(outputPath, "utf-8");
|
|
@@ -82192,7 +82480,7 @@ async function faqClassify(ctx, options) {
|
|
|
82192
82480
|
ctx.output.data(` Dry run: ${options.dryRun ?? false}`);
|
|
82193
82481
|
ctx.output.data("");
|
|
82194
82482
|
}
|
|
82195
|
-
if (!
|
|
82483
|
+
if (!existsSync9(parquetPath)) {
|
|
82196
82484
|
handleFaqClassifyError(
|
|
82197
82485
|
ctx,
|
|
82198
82486
|
new CLIError({
|
|
@@ -82203,7 +82491,7 @@ async function faqClassify(ctx, options) {
|
|
|
82203
82491
|
);
|
|
82204
82492
|
return;
|
|
82205
82493
|
}
|
|
82206
|
-
if (!
|
|
82494
|
+
if (!existsSync9(taxonomyPath)) {
|
|
82207
82495
|
handleFaqClassifyError(
|
|
82208
82496
|
ctx,
|
|
82209
82497
|
new CLIError({
|
|
@@ -82215,7 +82503,7 @@ async function faqClassify(ctx, options) {
|
|
|
82215
82503
|
return;
|
|
82216
82504
|
}
|
|
82217
82505
|
const outputDir = dirname2(outputPath);
|
|
82218
|
-
if (!
|
|
82506
|
+
if (!existsSync9(outputDir)) {
|
|
82219
82507
|
mkdirSync2(outputDir, { recursive: true });
|
|
82220
82508
|
}
|
|
82221
82509
|
if (!outputJson) ctx.output.data("\u{1F4DA} Loading taxonomy...");
|
|
@@ -82384,18 +82672,18 @@ function registerFaqClassifyCommands(program3) {
|
|
|
82384
82672
|
|
|
82385
82673
|
// src/commands/faq/cluster.ts
|
|
82386
82674
|
init_esm_shims();
|
|
82387
|
-
import { existsSync as
|
|
82388
|
-
import { join as
|
|
82675
|
+
import { existsSync as existsSync11 } from "fs";
|
|
82676
|
+
import { join as join10, resolve as resolve4 } from "path";
|
|
82389
82677
|
|
|
82390
82678
|
// ../core/src/faq/production-clusterer.ts
|
|
82391
82679
|
init_esm_shims();
|
|
82392
|
-
import { existsSync as
|
|
82393
|
-
import { join as
|
|
82680
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync3, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "fs";
|
|
82681
|
+
import { join as join9 } from "path";
|
|
82394
82682
|
function readPhase0Assignments(phase0Path) {
|
|
82395
|
-
const assignmentsPath =
|
|
82396
|
-
if (!
|
|
82397
|
-
const latestPath =
|
|
82398
|
-
if (!
|
|
82683
|
+
const assignmentsPath = join9(phase0Path, "clusters/v1/assignments.json");
|
|
82684
|
+
if (!existsSync10(assignmentsPath)) {
|
|
82685
|
+
const latestPath = join9(phase0Path, "clusters/latest/assignments.json");
|
|
82686
|
+
if (!existsSync10(latestPath)) {
|
|
82399
82687
|
throw new Error(`Phase 0 assignments not found at ${assignmentsPath}`);
|
|
82400
82688
|
}
|
|
82401
82689
|
const content2 = readFileSync8(latestPath, "utf-8");
|
|
@@ -82405,10 +82693,10 @@ function readPhase0Assignments(phase0Path) {
|
|
|
82405
82693
|
return JSON.parse(content);
|
|
82406
82694
|
}
|
|
82407
82695
|
function readPhase0Labels(phase0Path) {
|
|
82408
|
-
const labelsPath =
|
|
82409
|
-
if (!
|
|
82410
|
-
const latestPath =
|
|
82411
|
-
if (!
|
|
82696
|
+
const labelsPath = join9(phase0Path, "clusters/v1/labels.json");
|
|
82697
|
+
if (!existsSync10(labelsPath)) {
|
|
82698
|
+
const latestPath = join9(phase0Path, "clusters/latest/labels.json");
|
|
82699
|
+
if (!existsSync10(latestPath)) {
|
|
82412
82700
|
throw new Error(`Phase 0 labels not found at ${labelsPath}`);
|
|
82413
82701
|
}
|
|
82414
82702
|
const content2 = readFileSync8(latestPath, "utf-8");
|
|
@@ -82420,10 +82708,10 @@ function readPhase0Labels(phase0Path) {
|
|
|
82420
82708
|
return parsed.clusters || [];
|
|
82421
82709
|
}
|
|
82422
82710
|
function readPhase0Metrics(phase0Path) {
|
|
82423
|
-
const metricsPath =
|
|
82424
|
-
if (!
|
|
82425
|
-
const latestPath =
|
|
82426
|
-
if (!
|
|
82711
|
+
const metricsPath = join9(phase0Path, "clusters/v1/metrics.json");
|
|
82712
|
+
if (!existsSync10(metricsPath)) {
|
|
82713
|
+
const latestPath = join9(phase0Path, "clusters/latest/metrics.json");
|
|
82714
|
+
if (!existsSync10(latestPath)) {
|
|
82427
82715
|
throw new Error(`Phase 0 metrics not found at ${metricsPath}`);
|
|
82428
82716
|
}
|
|
82429
82717
|
return JSON.parse(readFileSync8(latestPath, "utf-8"));
|
|
@@ -82543,17 +82831,17 @@ async function generateProductionClustering(options) {
|
|
|
82543
82831
|
return result;
|
|
82544
82832
|
}
|
|
82545
82833
|
function writeProductionArtifacts(result, outputPath) {
|
|
82546
|
-
const versionPath =
|
|
82547
|
-
if (!
|
|
82834
|
+
const versionPath = join9(outputPath, result.version);
|
|
82835
|
+
if (!existsSync10(versionPath)) {
|
|
82548
82836
|
mkdirSync3(versionPath, { recursive: true });
|
|
82549
82837
|
}
|
|
82550
|
-
const resultPath =
|
|
82838
|
+
const resultPath = join9(versionPath, "clustering-result.json");
|
|
82551
82839
|
writeFileSync6(resultPath, JSON.stringify(result, null, 2));
|
|
82552
82840
|
console.log(`\u2705 Written: ${resultPath}`);
|
|
82553
|
-
const assignmentsPath =
|
|
82841
|
+
const assignmentsPath = join9(versionPath, "assignments.json");
|
|
82554
82842
|
writeFileSync6(assignmentsPath, JSON.stringify(result.assignments, null, 2));
|
|
82555
82843
|
console.log(`\u2705 Written: ${assignmentsPath}`);
|
|
82556
|
-
const clustersPath =
|
|
82844
|
+
const clustersPath = join9(versionPath, "clusters.json");
|
|
82557
82845
|
writeFileSync6(
|
|
82558
82846
|
clustersPath,
|
|
82559
82847
|
JSON.stringify(
|
|
@@ -82568,7 +82856,7 @@ function writeProductionArtifacts(result, outputPath) {
|
|
|
82568
82856
|
)
|
|
82569
82857
|
);
|
|
82570
82858
|
console.log(`\u2705 Written: ${clustersPath}`);
|
|
82571
|
-
const summaryPath =
|
|
82859
|
+
const summaryPath = join9(versionPath, "summary.json");
|
|
82572
82860
|
const summary = {
|
|
82573
82861
|
version: result.version,
|
|
82574
82862
|
generatedAt: result.generatedAt,
|
|
@@ -82582,8 +82870,8 @@ function writeProductionArtifacts(result, outputPath) {
|
|
|
82582
82870
|
};
|
|
82583
82871
|
writeFileSync6(summaryPath, JSON.stringify(summary, null, 2));
|
|
82584
82872
|
console.log(`\u2705 Written: ${summaryPath}`);
|
|
82585
|
-
const latestPath =
|
|
82586
|
-
if (
|
|
82873
|
+
const latestPath = join9(outputPath, "latest");
|
|
82874
|
+
if (existsSync10(latestPath)) {
|
|
82587
82875
|
const { rmSync: rmSync2 } = __require("fs");
|
|
82588
82876
|
rmSync2(latestPath, { recursive: true, force: true });
|
|
82589
82877
|
}
|
|
@@ -82594,8 +82882,8 @@ function writeProductionArtifacts(result, outputPath) {
|
|
|
82594
82882
|
"clusters.json",
|
|
82595
82883
|
"summary.json"
|
|
82596
82884
|
]) {
|
|
82597
|
-
const src =
|
|
82598
|
-
const dst =
|
|
82885
|
+
const src = join9(versionPath, file);
|
|
82886
|
+
const dst = join9(latestPath, file);
|
|
82599
82887
|
writeFileSync6(dst, readFileSync8(src));
|
|
82600
82888
|
}
|
|
82601
82889
|
console.log(`\u2705 Updated: ${latestPath}`);
|
|
@@ -82648,25 +82936,25 @@ function displayClusteringSummary(result) {
|
|
|
82648
82936
|
|
|
82649
82937
|
// src/commands/faq/cluster.ts
|
|
82650
82938
|
var PROJECT_ROOT2 = resolve4(__dirname, "../../../..");
|
|
82651
|
-
var DEFAULT_PHASE0_PATH =
|
|
82652
|
-
var DEFAULT_OUTPUT_PATH2 =
|
|
82939
|
+
var DEFAULT_PHASE0_PATH = join10(PROJECT_ROOT2, "artifacts/phase-0");
|
|
82940
|
+
var DEFAULT_OUTPUT_PATH2 = join10(PROJECT_ROOT2, "artifacts/phase-1/clustering");
|
|
82653
82941
|
function validatePaths(phase0Path) {
|
|
82654
|
-
const assignmentsPath =
|
|
82655
|
-
const labelsPath =
|
|
82656
|
-
const metricsPath =
|
|
82657
|
-
if (!
|
|
82942
|
+
const assignmentsPath = join10(phase0Path, "clusters/v1/assignments.json");
|
|
82943
|
+
const labelsPath = join10(phase0Path, "clusters/v1/labels.json");
|
|
82944
|
+
const metricsPath = join10(phase0Path, "clusters/v1/metrics.json");
|
|
82945
|
+
if (!existsSync11(assignmentsPath)) {
|
|
82658
82946
|
throw new CLIError({
|
|
82659
82947
|
userMessage: `Phase 0 assignments not found at ${assignmentsPath}.`,
|
|
82660
82948
|
suggestion: "Run Phase 0 clustering first or specify the correct --phase0-path."
|
|
82661
82949
|
});
|
|
82662
82950
|
}
|
|
82663
|
-
if (!
|
|
82951
|
+
if (!existsSync11(labelsPath)) {
|
|
82664
82952
|
throw new CLIError({
|
|
82665
82953
|
userMessage: `Phase 0 labels not found at ${labelsPath}.`,
|
|
82666
82954
|
suggestion: "Verify the --phase0-path points to valid artifacts."
|
|
82667
82955
|
});
|
|
82668
82956
|
}
|
|
82669
|
-
if (!
|
|
82957
|
+
if (!existsSync11(metricsPath)) {
|
|
82670
82958
|
throw new CLIError({
|
|
82671
82959
|
userMessage: `Phase 0 metrics not found at ${metricsPath}.`,
|
|
82672
82960
|
suggestion: "Verify the --phase0-path points to valid artifacts."
|
|
@@ -82704,7 +82992,7 @@ async function faqCluster(ctx, options) {
|
|
|
82704
82992
|
writeProductionArtifacts(result, outputPath);
|
|
82705
82993
|
if (!outputJson) {
|
|
82706
82994
|
ctx.output.data("\n\u2705 Production clustering complete!");
|
|
82707
|
-
ctx.output.data(` Artifacts written to: ${
|
|
82995
|
+
ctx.output.data(` Artifacts written to: ${join10(outputPath, version)}`);
|
|
82708
82996
|
}
|
|
82709
82997
|
} else {
|
|
82710
82998
|
if (!outputJson) ctx.output.data("\n\u{1F9EA} Dry run - no artifacts written");
|
|
@@ -82747,13 +83035,13 @@ function registerFaqClusterCommands(program3) {
|
|
|
82747
83035
|
|
|
82748
83036
|
// src/commands/faq/extract.ts
|
|
82749
83037
|
init_esm_shims();
|
|
82750
|
-
import { existsSync as
|
|
82751
|
-
import { join as
|
|
83038
|
+
import { existsSync as existsSync13 } from "fs";
|
|
83039
|
+
import { join as join12, resolve as resolve5 } from "path";
|
|
82752
83040
|
|
|
82753
83041
|
// ../core/src/faq/extractor.ts
|
|
82754
83042
|
init_esm_shims();
|
|
82755
|
-
import { existsSync as
|
|
82756
|
-
import { join as
|
|
83043
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync4, readFileSync as readFileSync9, writeFileSync as writeFileSync7 } from "fs";
|
|
83044
|
+
import { join as join11 } from "path";
|
|
82757
83045
|
|
|
82758
83046
|
// ../core/src/faq/review.ts
|
|
82759
83047
|
init_esm_shims();
|
|
@@ -83367,14 +83655,14 @@ async function extractFaqCandidates(options) {
|
|
|
83367
83655
|
return result;
|
|
83368
83656
|
}
|
|
83369
83657
|
function writeExtractionArtifacts(result, outputPath) {
|
|
83370
|
-
const versionPath =
|
|
83371
|
-
if (!
|
|
83658
|
+
const versionPath = join11(outputPath, result.version);
|
|
83659
|
+
if (!existsSync12(versionPath)) {
|
|
83372
83660
|
mkdirSync4(versionPath, { recursive: true });
|
|
83373
83661
|
}
|
|
83374
|
-
const resultPath =
|
|
83662
|
+
const resultPath = join11(versionPath, "extraction-result.json");
|
|
83375
83663
|
writeFileSync7(resultPath, JSON.stringify(result, null, 2));
|
|
83376
83664
|
console.log(`\u2705 Written: ${resultPath}`);
|
|
83377
|
-
const candidatesPath =
|
|
83665
|
+
const candidatesPath = join11(versionPath, "candidates.json");
|
|
83378
83666
|
const candidatesData = {
|
|
83379
83667
|
version: result.version,
|
|
83380
83668
|
extractedAt: result.extractedAt,
|
|
@@ -83394,7 +83682,7 @@ function writeExtractionArtifacts(result, outputPath) {
|
|
|
83394
83682
|
};
|
|
83395
83683
|
writeFileSync7(candidatesPath, JSON.stringify(candidatesData, null, 2));
|
|
83396
83684
|
console.log(`\u2705 Written: ${candidatesPath}`);
|
|
83397
|
-
const statsPath =
|
|
83685
|
+
const statsPath = join11(versionPath, "stats.json");
|
|
83398
83686
|
writeFileSync7(
|
|
83399
83687
|
statsPath,
|
|
83400
83688
|
JSON.stringify(
|
|
@@ -83408,8 +83696,8 @@ function writeExtractionArtifacts(result, outputPath) {
|
|
|
83408
83696
|
)
|
|
83409
83697
|
);
|
|
83410
83698
|
console.log(`\u2705 Written: ${statsPath}`);
|
|
83411
|
-
const latestPath =
|
|
83412
|
-
if (
|
|
83699
|
+
const latestPath = join11(outputPath, "latest");
|
|
83700
|
+
if (existsSync12(latestPath)) {
|
|
83413
83701
|
const { rmSync: rmSync2 } = __require("fs");
|
|
83414
83702
|
rmSync2(latestPath, { recursive: true, force: true });
|
|
83415
83703
|
}
|
|
@@ -83419,9 +83707,9 @@ function writeExtractionArtifacts(result, outputPath) {
|
|
|
83419
83707
|
"candidates.json",
|
|
83420
83708
|
"stats.json"
|
|
83421
83709
|
]) {
|
|
83422
|
-
const src =
|
|
83423
|
-
const dst =
|
|
83424
|
-
if (
|
|
83710
|
+
const src = join11(versionPath, file);
|
|
83711
|
+
const dst = join11(latestPath, file);
|
|
83712
|
+
if (existsSync12(src)) {
|
|
83425
83713
|
writeFileSync7(dst, readFileSync9(src));
|
|
83426
83714
|
}
|
|
83427
83715
|
}
|
|
@@ -83475,24 +83763,24 @@ ${i + 1}. [${confPct}%]${golden} ${candidate.suggestedCategory}`
|
|
|
83475
83763
|
|
|
83476
83764
|
// src/commands/faq/extract.ts
|
|
83477
83765
|
var PROJECT_ROOT3 = resolve5(__dirname, "../../../..");
|
|
83478
|
-
var DEFAULT_CLUSTERING_PATH =
|
|
83766
|
+
var DEFAULT_CLUSTERING_PATH = join12(
|
|
83479
83767
|
PROJECT_ROOT3,
|
|
83480
83768
|
"artifacts/phase-1/clustering/v1/clustering-result.json"
|
|
83481
83769
|
);
|
|
83482
|
-
var DEFAULT_GOLDEN_PATH =
|
|
83770
|
+
var DEFAULT_GOLDEN_PATH = join12(
|
|
83483
83771
|
PROJECT_ROOT3,
|
|
83484
83772
|
"artifacts/phase-0/golden/latest/responses.json"
|
|
83485
83773
|
);
|
|
83486
|
-
var DEFAULT_OUTPUT_PATH3 =
|
|
83774
|
+
var DEFAULT_OUTPUT_PATH3 = join12(PROJECT_ROOT3, "artifacts/phase-1/extraction");
|
|
83487
83775
|
var DEFAULT_CACHE_PATH = `${process.env.HOME}/skill/data/front-cache.db`;
|
|
83488
83776
|
function validatePaths2(ctx, clusteringPath, goldenPath, outputJson) {
|
|
83489
|
-
if (!
|
|
83777
|
+
if (!existsSync13(clusteringPath)) {
|
|
83490
83778
|
throw new CLIError({
|
|
83491
83779
|
userMessage: `Clustering result not found at ${clusteringPath}.`,
|
|
83492
83780
|
suggestion: "Run `bun src/index.ts faq cluster` first to generate clustering."
|
|
83493
83781
|
});
|
|
83494
83782
|
}
|
|
83495
|
-
if (goldenPath && !
|
|
83783
|
+
if (goldenPath && !existsSync13(goldenPath)) {
|
|
83496
83784
|
if (!outputJson) {
|
|
83497
83785
|
ctx.output.warn(`Golden responses not found at ${goldenPath}`);
|
|
83498
83786
|
ctx.output.warn("Golden matching will be disabled.");
|
|
@@ -83521,7 +83809,7 @@ async function faqExtract(ctx, options) {
|
|
|
83521
83809
|
ctx.output.data("");
|
|
83522
83810
|
}
|
|
83523
83811
|
validatePaths2(ctx, clusteringPath, goldenPath, outputJson);
|
|
83524
|
-
if (!
|
|
83812
|
+
if (!existsSync13(cachePath)) {
|
|
83525
83813
|
const cliError = new CLIError({
|
|
83526
83814
|
userMessage: `DuckDB cache not found at ${cachePath}.`,
|
|
83527
83815
|
suggestion: "Run `bun src/index.ts front-cache sync` first to populate cache."
|
|
@@ -83543,7 +83831,7 @@ async function faqExtract(ctx, options) {
|
|
|
83543
83831
|
}
|
|
83544
83832
|
const extractionOptions = {
|
|
83545
83833
|
clusteringPath,
|
|
83546
|
-
goldenPath:
|
|
83834
|
+
goldenPath: existsSync13(goldenPath) ? goldenPath : void 0,
|
|
83547
83835
|
source,
|
|
83548
83836
|
outputPath,
|
|
83549
83837
|
version,
|
|
@@ -83588,7 +83876,7 @@ async function faqExtract(ctx, options) {
|
|
|
83588
83876
|
if (!options.dryRun) {
|
|
83589
83877
|
ctx.output.data(`
|
|
83590
83878
|
\u2705 Extraction complete!`);
|
|
83591
|
-
ctx.output.data(` Artifacts written to: ${
|
|
83879
|
+
ctx.output.data(` Artifacts written to: ${join12(outputPath, version)}`);
|
|
83592
83880
|
if (options.pushRedis && options.app) {
|
|
83593
83881
|
ctx.output.data(
|
|
83594
83882
|
` Candidates pushed to Redis queue: faq:pending:${options.app}`
|
|
@@ -92617,9 +92905,9 @@ function registerFaqMineCommands(program3) {
|
|
|
92617
92905
|
// src/commands/faq/review.ts
|
|
92618
92906
|
init_esm_shims();
|
|
92619
92907
|
import { spawnSync } from "child_process";
|
|
92620
|
-
import { existsSync as
|
|
92908
|
+
import { existsSync as existsSync14, readFileSync as readFileSync10, unlinkSync, writeFileSync as writeFileSync9 } from "fs";
|
|
92621
92909
|
import { tmpdir } from "os";
|
|
92622
|
-
import { join as
|
|
92910
|
+
import { join as join13 } from "path";
|
|
92623
92911
|
import { confirm as confirm2, select as select3 } from "@inquirer/prompts";
|
|
92624
92912
|
var COLORS2 = {
|
|
92625
92913
|
reset: "\x1B[0m",
|
|
@@ -92680,7 +92968,7 @@ function getEditor() {
|
|
|
92680
92968
|
}
|
|
92681
92969
|
function editInEditor(ctx, question, answer) {
|
|
92682
92970
|
const editor = getEditor();
|
|
92683
|
-
const tmpFile =
|
|
92971
|
+
const tmpFile = join13(tmpdir(), `faq-edit-${Date.now()}.md`);
|
|
92684
92972
|
const content = `# FAQ Edit
|
|
92685
92973
|
|
|
92686
92974
|
## Question
|
|
@@ -92723,7 +93011,7 @@ The sections are separated by "## Question" and "## Answer" headers.
|
|
|
92723
93011
|
answer: editedAnswer
|
|
92724
93012
|
};
|
|
92725
93013
|
} finally {
|
|
92726
|
-
if (
|
|
93014
|
+
if (existsSync14(tmpFile)) {
|
|
92727
93015
|
unlinkSync(tmpFile);
|
|
92728
93016
|
}
|
|
92729
93017
|
}
|
|
@@ -94707,7 +94995,10 @@ async function listInboxes(ctx, options) {
|
|
|
94707
94995
|
const idsOnly = options.idsOnly === true;
|
|
94708
94996
|
try {
|
|
94709
94997
|
const front = getFrontClient(ctx);
|
|
94710
|
-
const inboxList = await
|
|
94998
|
+
const inboxList = await withSpinner(
|
|
94999
|
+
"Loading inboxes...",
|
|
95000
|
+
() => front.inboxes.list()
|
|
95001
|
+
);
|
|
94711
95002
|
const inboxes = inboxList._results ?? [];
|
|
94712
95003
|
if (idsOnly) {
|
|
94713
95004
|
for (const inbox of inboxes) {
|
|
@@ -94771,7 +95062,10 @@ async function listConversations(ctx, inboxNameOrId, options) {
|
|
|
94771
95062
|
const idsOnly = options.idsOnly === true;
|
|
94772
95063
|
try {
|
|
94773
95064
|
const front = getFrontClient(ctx);
|
|
94774
|
-
const inbox = await
|
|
95065
|
+
const inbox = await withSpinner(
|
|
95066
|
+
"Finding inbox...",
|
|
95067
|
+
() => findInbox(ctx, inboxNameOrId)
|
|
95068
|
+
);
|
|
94775
95069
|
if (!inbox) {
|
|
94776
95070
|
throw new CLIError({
|
|
94777
95071
|
userMessage: `Inbox not found: ${inboxNameOrId}`,
|
|
@@ -97235,7 +97529,10 @@ async function listEvents(ctx, options) {
|
|
|
97235
97529
|
});
|
|
97236
97530
|
}
|
|
97237
97531
|
params.limit = limit2;
|
|
97238
|
-
const response = await
|
|
97532
|
+
const response = await withSpinner(
|
|
97533
|
+
"Loading events...",
|
|
97534
|
+
() => client.listEvents(params)
|
|
97535
|
+
);
|
|
97239
97536
|
if (outputJson) {
|
|
97240
97537
|
ctx.output.data(response.data);
|
|
97241
97538
|
} else {
|
|
@@ -97258,10 +97555,10 @@ async function getEvent(ctx, id, options) {
|
|
|
97258
97555
|
const outputJson = options.json === true || ctx.format === "json";
|
|
97259
97556
|
try {
|
|
97260
97557
|
const client = new InngestClient({ dev: options.dev });
|
|
97261
|
-
const [event, runs] = await
|
|
97262
|
-
|
|
97263
|
-
client.getEventRuns(id)
|
|
97264
|
-
|
|
97558
|
+
const [event, runs] = await withSpinner(
|
|
97559
|
+
"Loading event...",
|
|
97560
|
+
() => Promise.all([client.getEvent(id), client.getEventRuns(id)])
|
|
97561
|
+
);
|
|
97265
97562
|
if (outputJson) {
|
|
97266
97563
|
ctx.output.data({ event, runs });
|
|
97267
97564
|
} else {
|
|
@@ -97666,6 +97963,154 @@ function registerInvestigateCommands(inngest) {
|
|
|
97666
97963
|
});
|
|
97667
97964
|
}
|
|
97668
97965
|
|
|
97966
|
+
// src/commands/inngest/patterns.ts
|
|
97967
|
+
init_esm_shims();
|
|
97968
|
+
async function patterns(ctx, options) {
|
|
97969
|
+
const outputJson = options.json === true || ctx.format === "json";
|
|
97970
|
+
try {
|
|
97971
|
+
const client = new InngestClient({ dev: options.dev });
|
|
97972
|
+
const params = { limit: 100 };
|
|
97973
|
+
if (options.after) {
|
|
97974
|
+
params.received_after = parseTimeArg(options.after);
|
|
97975
|
+
}
|
|
97976
|
+
const events = outputJson ? await client.listEvents(params) : await withSpinner("Fetching events...", () => client.listEvents(params));
|
|
97977
|
+
const byName = {};
|
|
97978
|
+
const byFunction = {};
|
|
97979
|
+
for (const event of events.data) {
|
|
97980
|
+
byName[event.name] = (byName[event.name] || 0) + 1;
|
|
97981
|
+
if (event.name === "inngest/function.finished") {
|
|
97982
|
+
const data2 = event.data;
|
|
97983
|
+
const functionId = data2?.function_id;
|
|
97984
|
+
if (!functionId) continue;
|
|
97985
|
+
if (!byFunction[functionId]) {
|
|
97986
|
+
byFunction[functionId] = { success: 0, failed: 0 };
|
|
97987
|
+
}
|
|
97988
|
+
if (data2.error || data2._inngest?.status === "Failed") {
|
|
97989
|
+
byFunction[functionId].failed++;
|
|
97990
|
+
} else {
|
|
97991
|
+
byFunction[functionId].success++;
|
|
97992
|
+
}
|
|
97993
|
+
}
|
|
97994
|
+
}
|
|
97995
|
+
const timeRangeHours = options.after ? parseTimeWindow(options.after) : 24;
|
|
97996
|
+
const topEvents = Object.entries(byName).map(([name, count]) => ({
|
|
97997
|
+
name,
|
|
97998
|
+
count,
|
|
97999
|
+
frequency_per_hour: count / timeRangeHours
|
|
98000
|
+
})).sort((a, b) => b.count - a.count).slice(0, 10);
|
|
98001
|
+
const functionStats = {};
|
|
98002
|
+
for (const [functionId, stats4] of Object.entries(byFunction)) {
|
|
98003
|
+
const total = stats4.success + stats4.failed;
|
|
98004
|
+
functionStats[functionId] = {
|
|
98005
|
+
success: stats4.success,
|
|
98006
|
+
failed: stats4.failed,
|
|
98007
|
+
success_rate: total > 0 ? stats4.success / total : 0
|
|
98008
|
+
};
|
|
98009
|
+
}
|
|
98010
|
+
const output = {
|
|
98011
|
+
time_range: options.after || "24h",
|
|
98012
|
+
total_events: events.data.length,
|
|
98013
|
+
events_by_name: byName,
|
|
98014
|
+
by_function: functionStats,
|
|
98015
|
+
top_events: topEvents
|
|
98016
|
+
};
|
|
98017
|
+
if (outputJson) {
|
|
98018
|
+
ctx.output.data(output);
|
|
98019
|
+
} else {
|
|
98020
|
+
const lines = [];
|
|
98021
|
+
lines.push("\nEvent Patterns\n");
|
|
98022
|
+
lines.push(`Time range: ${output.time_range}`);
|
|
98023
|
+
lines.push(`Total events: ${output.total_events}
|
|
98024
|
+
`);
|
|
98025
|
+
lines.push("Top Events:");
|
|
98026
|
+
lines.push(
|
|
98027
|
+
"\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"
|
|
98028
|
+
);
|
|
98029
|
+
lines.push(
|
|
98030
|
+
"\u2502 Event Name \u2502 Count \u2502 Per Hour \u2502"
|
|
98031
|
+
);
|
|
98032
|
+
lines.push(
|
|
98033
|
+
"\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"
|
|
98034
|
+
);
|
|
98035
|
+
for (const event of topEvents) {
|
|
98036
|
+
const name = event.name.padEnd(38).slice(0, 38);
|
|
98037
|
+
const count = String(event.count).padStart(5);
|
|
98038
|
+
const freq = event.frequency_per_hour.toFixed(2).padStart(12);
|
|
98039
|
+
lines.push(`\u2502 ${name} \u2502 ${count} \u2502 ${freq} \u2502`);
|
|
98040
|
+
}
|
|
98041
|
+
lines.push(
|
|
98042
|
+
"\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n"
|
|
98043
|
+
);
|
|
98044
|
+
if (Object.keys(functionStats).length > 0) {
|
|
98045
|
+
lines.push("Function Stats:");
|
|
98046
|
+
lines.push(
|
|
98047
|
+
"\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"
|
|
98048
|
+
);
|
|
98049
|
+
lines.push(
|
|
98050
|
+
"\u2502 Function \u2502 Success \u2502 Failed \u2502 Success % \u2502"
|
|
98051
|
+
);
|
|
98052
|
+
lines.push(
|
|
98053
|
+
"\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524"
|
|
98054
|
+
);
|
|
98055
|
+
for (const [functionId, stats4] of Object.entries(functionStats)) {
|
|
98056
|
+
const name = functionId.padEnd(38).slice(0, 38);
|
|
98057
|
+
const success = String(stats4.success).padStart(7);
|
|
98058
|
+
const failed = String(stats4.failed).padStart(6);
|
|
98059
|
+
const rate = `${(stats4.success_rate * 100).toFixed(1)}%`.padStart(11);
|
|
98060
|
+
lines.push(`\u2502 ${name} \u2502 ${success} \u2502 ${failed} \u2502 ${rate} \u2502`);
|
|
98061
|
+
}
|
|
98062
|
+
lines.push(
|
|
98063
|
+
"\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n"
|
|
98064
|
+
);
|
|
98065
|
+
}
|
|
98066
|
+
lines.push(
|
|
98067
|
+
"Use `skill inngest failures` for detailed failure analysis.\n"
|
|
98068
|
+
);
|
|
98069
|
+
ctx.output.data(lines.join("\n"));
|
|
98070
|
+
}
|
|
98071
|
+
} catch (error) {
|
|
98072
|
+
const cliError = error instanceof CLIError ? error : new CLIError({
|
|
98073
|
+
userMessage: "Failed to analyze Inngest patterns.",
|
|
98074
|
+
suggestion: "Verify INNGEST_SIGNING_KEY and time window.",
|
|
98075
|
+
cause: error
|
|
98076
|
+
});
|
|
98077
|
+
ctx.output.error(formatError(cliError));
|
|
98078
|
+
process.exitCode = cliError.exitCode;
|
|
98079
|
+
}
|
|
98080
|
+
}
|
|
98081
|
+
function parseTimeWindow(input2) {
|
|
98082
|
+
const match = input2.match(/^(\d+)([hmd])$/);
|
|
98083
|
+
if (!match) return 24;
|
|
98084
|
+
const [, num, unit] = match;
|
|
98085
|
+
const value = Number.parseInt(num ?? "24", 10);
|
|
98086
|
+
switch (unit) {
|
|
98087
|
+
case "h":
|
|
98088
|
+
return value;
|
|
98089
|
+
case "d":
|
|
98090
|
+
return value * 24;
|
|
98091
|
+
case "m":
|
|
98092
|
+
return value / 60;
|
|
98093
|
+
default:
|
|
98094
|
+
return 24;
|
|
98095
|
+
}
|
|
98096
|
+
}
|
|
98097
|
+
function registerPatternsCommand(inngest) {
|
|
98098
|
+
inngest.command("patterns").description(
|
|
98099
|
+
"Aggregate event analysis (event distribution, function success rates)"
|
|
98100
|
+
).option("--after <time>", 'Time window (e.g., "2h", "1d")', "24h").option("--json", "Output as JSON").option("--dev", "Use dev server").action(async (options, command) => {
|
|
98101
|
+
const opts = typeof command.optsWithGlobals === "function" ? command.optsWithGlobals() : {
|
|
98102
|
+
...command.parent?.opts(),
|
|
98103
|
+
...command.opts()
|
|
98104
|
+
};
|
|
98105
|
+
const ctx = await createContext({
|
|
98106
|
+
format: options.json ? "json" : opts.format,
|
|
98107
|
+
verbose: opts.verbose,
|
|
98108
|
+
quiet: opts.quiet
|
|
98109
|
+
});
|
|
98110
|
+
await patterns(ctx, options);
|
|
98111
|
+
});
|
|
98112
|
+
}
|
|
98113
|
+
|
|
97669
98114
|
// src/commands/inngest/runs.ts
|
|
97670
98115
|
init_esm_shims();
|
|
97671
98116
|
import { confirm as confirm4 } from "@inquirer/prompts";
|
|
@@ -97691,7 +98136,7 @@ async function runCommand(ctx, id, options) {
|
|
|
97691
98136
|
try {
|
|
97692
98137
|
const isDev = options.dev ?? await detectDevServer();
|
|
97693
98138
|
const client = new InngestClient({ dev: isDev });
|
|
97694
|
-
const run3 = await client.getRun(id);
|
|
98139
|
+
const run3 = await withSpinner("Loading run...", () => client.getRun(id));
|
|
97695
98140
|
if (outputJson) {
|
|
97696
98141
|
ctx.output.data(run3);
|
|
97697
98142
|
} else {
|
|
@@ -97855,11 +98300,16 @@ function registerSignalCommand(inngest) {
|
|
|
97855
98300
|
|
|
97856
98301
|
// src/commands/inngest/index.ts
|
|
97857
98302
|
function registerInngestCommands(program3, usageState2) {
|
|
97858
|
-
const
|
|
98303
|
+
const baseDescription = getInngestAdaptiveDescription(usageState2);
|
|
98304
|
+
const descriptionWithEnv = `${baseDescription}
|
|
98305
|
+
|
|
98306
|
+
Environment: INNGEST_SIGNING_KEY required. Run \`skill doctor\` to check.`;
|
|
98307
|
+
const inngest = program3.command("inngest").description(descriptionWithEnv);
|
|
97859
98308
|
registerEventsCommands(inngest);
|
|
97860
98309
|
registerRunsCommands(inngest);
|
|
97861
98310
|
registerSignalCommand(inngest);
|
|
97862
98311
|
registerInvestigateCommands(inngest);
|
|
98312
|
+
registerPatternsCommand(inngest);
|
|
97863
98313
|
}
|
|
97864
98314
|
|
|
97865
98315
|
// src/commands/kb-sync.ts
|
|
@@ -113888,7 +114338,7 @@ function registerKbCommands(program3) {
|
|
|
113888
114338
|
|
|
113889
114339
|
// src/commands/keys/index.ts
|
|
113890
114340
|
init_esm_shims();
|
|
113891
|
-
import { existsSync as
|
|
114341
|
+
import { existsSync as existsSync15, readFileSync as readFileSync12 } from "fs";
|
|
113892
114342
|
import { password as password2, select as select5 } from "@inquirer/prompts";
|
|
113893
114343
|
import { Decrypter as Decrypter4 } from "age-encryption";
|
|
113894
114344
|
var buildContext4 = async (command, json) => {
|
|
@@ -113905,7 +114355,7 @@ var buildContext4 = async (command, json) => {
|
|
|
113905
114355
|
async function getUserConfiguredKeys() {
|
|
113906
114356
|
const keyPath = getAgeKeyPath();
|
|
113907
114357
|
const configPath = getEncryptedConfigPath();
|
|
113908
|
-
if (!
|
|
114358
|
+
if (!existsSync15(keyPath) || !existsSync15(configPath)) {
|
|
113909
114359
|
return /* @__PURE__ */ new Set();
|
|
113910
114360
|
}
|
|
113911
114361
|
try {
|
|
@@ -113973,7 +114423,7 @@ async function showKeyStatus(ctx) {
|
|
|
113973
114423
|
}
|
|
113974
114424
|
async function interactiveKeySetup(ctx) {
|
|
113975
114425
|
const keyPath = getAgeKeyPath();
|
|
113976
|
-
if (!
|
|
114426
|
+
if (!existsSync15(keyPath)) {
|
|
113977
114427
|
ctx.output.data("\n\u{1F511} First time setup - creating your encryption key...\n");
|
|
113978
114428
|
await configInitAction(ctx, { json: false });
|
|
113979
114429
|
ctx.output.data("");
|
|
@@ -114066,7 +114516,7 @@ function registerKeysCommands(program3) {
|
|
|
114066
114516
|
).option("--json", "Output as JSON").action(async (keyValue, options, command) => {
|
|
114067
114517
|
const ctx = await buildContext4(command, options.json);
|
|
114068
114518
|
const keyPath = getAgeKeyPath();
|
|
114069
|
-
if (!
|
|
114519
|
+
if (!existsSync15(keyPath)) {
|
|
114070
114520
|
if (process.stdin.isTTY && !options.json) {
|
|
114071
114521
|
ctx.output.data(
|
|
114072
114522
|
"\u{1F511} First time setup - creating your encryption key...\n"
|
|
@@ -114094,6 +114544,133 @@ function registerKeysCommands(program3) {
|
|
|
114094
114544
|
}
|
|
114095
114545
|
}
|
|
114096
114546
|
});
|
|
114547
|
+
keys.command("setup").description("Set up keychain + shell integration (tries everything)").option("--json", "Output as JSON").action(async (options, command) => {
|
|
114548
|
+
const ctx = await buildContext4(command, options.json);
|
|
114549
|
+
const outputJson = options.json || ctx.format === "json";
|
|
114550
|
+
const OP_VAULT_LINK = "https://start.1password.com/open/i?a=GCTJE4MRGFHKRAYXCEXKZKCEFU&v=u3ujzar6l3nahlahsuzfvg7vcq&i=3e4ip354ps3mhq2wwt6vmtm2zu&h=egghead.1password.com";
|
|
114551
|
+
const status = getKeychainStatus();
|
|
114552
|
+
const steps = [];
|
|
114553
|
+
const errors2 = [];
|
|
114554
|
+
if (status.opTokenInKeychain && status.ageKeyInKeychain && status.shellIntegration) {
|
|
114555
|
+
if (outputJson) {
|
|
114556
|
+
ctx.output.data({ success: true, status: "configured" });
|
|
114557
|
+
} else {
|
|
114558
|
+
ctx.output.data("\u2713 Already configured");
|
|
114559
|
+
}
|
|
114560
|
+
return;
|
|
114561
|
+
}
|
|
114562
|
+
let opToken = null;
|
|
114563
|
+
if (process.env.OP_SERVICE_ACCOUNT_TOKEN) {
|
|
114564
|
+
opToken = process.env.OP_SERVICE_ACCOUNT_TOKEN;
|
|
114565
|
+
steps.push("\u2713 OP token from env");
|
|
114566
|
+
}
|
|
114567
|
+
if (!opToken) {
|
|
114568
|
+
const { getFromKeychain: getFromKeychain2 } = await import("./keychain-IEZHT5WN.js");
|
|
114569
|
+
opToken = getFromKeychain2("op-service-account-token");
|
|
114570
|
+
if (opToken) steps.push("\u2713 OP token from keychain");
|
|
114571
|
+
}
|
|
114572
|
+
if (!opToken && status.opCliAvailable) {
|
|
114573
|
+
opToken = autoBootstrapKeychain();
|
|
114574
|
+
if (opToken) steps.push("\u2713 OP token from op CLI");
|
|
114575
|
+
}
|
|
114576
|
+
if (opToken && !status.opTokenInKeychain && isKeychainSupported()) {
|
|
114577
|
+
if (storeInKeychain("op-service-account-token", opToken)) {
|
|
114578
|
+
steps.push("\u2713 OP token \u2192 keychain");
|
|
114579
|
+
} else {
|
|
114580
|
+
errors2.push("Could not store OP token in keychain");
|
|
114581
|
+
}
|
|
114582
|
+
}
|
|
114583
|
+
let ageKey = null;
|
|
114584
|
+
if (process.env.SKILL_AGE_KEY) {
|
|
114585
|
+
ageKey = process.env.SKILL_AGE_KEY;
|
|
114586
|
+
steps.push("\u2713 Age key from env");
|
|
114587
|
+
}
|
|
114588
|
+
if (!ageKey) {
|
|
114589
|
+
const { getFromKeychain: getFromKeychain2 } = await import("./keychain-IEZHT5WN.js");
|
|
114590
|
+
ageKey = getFromKeychain2("age-private-key");
|
|
114591
|
+
if (ageKey) steps.push("\u2713 Age key from keychain");
|
|
114592
|
+
}
|
|
114593
|
+
if (!ageKey && opToken) {
|
|
114594
|
+
const originalEnv = process.env.OP_SERVICE_ACCOUNT_TOKEN;
|
|
114595
|
+
process.env.OP_SERVICE_ACCOUNT_TOKEN = opToken;
|
|
114596
|
+
try {
|
|
114597
|
+
const { OnePasswordProvider: OnePasswordProvider2 } = await import("./secrets-MGVPGMFJ.js");
|
|
114598
|
+
const op = new OnePasswordProvider2();
|
|
114599
|
+
if (await op.isAvailable()) {
|
|
114600
|
+
ageKey = await op.resolve(
|
|
114601
|
+
"op://Support/skill-cli-age-key/private_key"
|
|
114602
|
+
);
|
|
114603
|
+
if (ageKey) steps.push("\u2713 Age key from 1Password");
|
|
114604
|
+
}
|
|
114605
|
+
} catch {
|
|
114606
|
+
errors2.push("1Password SDK failed");
|
|
114607
|
+
} finally {
|
|
114608
|
+
if (originalEnv) {
|
|
114609
|
+
process.env.OP_SERVICE_ACCOUNT_TOKEN = originalEnv;
|
|
114610
|
+
} else {
|
|
114611
|
+
delete process.env.OP_SERVICE_ACCOUNT_TOKEN;
|
|
114612
|
+
}
|
|
114613
|
+
}
|
|
114614
|
+
}
|
|
114615
|
+
if (ageKey && !status.ageKeyInKeychain && isKeychainSupported()) {
|
|
114616
|
+
if (storeInKeychain("age-private-key", ageKey)) {
|
|
114617
|
+
steps.push("\u2713 Age key \u2192 keychain");
|
|
114618
|
+
} else {
|
|
114619
|
+
errors2.push("Could not store age key in keychain");
|
|
114620
|
+
}
|
|
114621
|
+
}
|
|
114622
|
+
if (!status.shellIntegration && isKeychainSupported()) {
|
|
114623
|
+
const r = addShellIntegration();
|
|
114624
|
+
if (r.success) {
|
|
114625
|
+
steps.push(`\u2713 Shell \u2192 ${r.path}`);
|
|
114626
|
+
} else {
|
|
114627
|
+
errors2.push(`Shell integration: ${r.error}`);
|
|
114628
|
+
}
|
|
114629
|
+
}
|
|
114630
|
+
const finalStatus = getKeychainStatus();
|
|
114631
|
+
const success = finalStatus.opTokenInKeychain && finalStatus.ageKeyInKeychain;
|
|
114632
|
+
if (outputJson) {
|
|
114633
|
+
ctx.output.data({ success, steps, errors: errors2, status: finalStatus });
|
|
114634
|
+
return;
|
|
114635
|
+
}
|
|
114636
|
+
for (const s of steps) {
|
|
114637
|
+
ctx.output.data(s);
|
|
114638
|
+
}
|
|
114639
|
+
if (success) {
|
|
114640
|
+
ctx.output.data("");
|
|
114641
|
+
ctx.output.data("\u2713 Done! Run: source ~/.zshrc");
|
|
114642
|
+
return;
|
|
114643
|
+
}
|
|
114644
|
+
ctx.output.data("");
|
|
114645
|
+
ctx.output.data("\u2500".repeat(50));
|
|
114646
|
+
ctx.output.data("Could not complete automatic setup. Manual steps:");
|
|
114647
|
+
ctx.output.data("");
|
|
114648
|
+
if (!opToken) {
|
|
114649
|
+
ctx.output.data("1. Get OP_SERVICE_ACCOUNT_TOKEN:");
|
|
114650
|
+
ctx.output.data(` open "${OP_VAULT_LINK}"`);
|
|
114651
|
+
ctx.output.data(' Copy the "credential" field');
|
|
114652
|
+
ctx.output.data("");
|
|
114653
|
+
ctx.output.data("2. Add to ~/.zshrc:");
|
|
114654
|
+
ctx.output.data(' export OP_SERVICE_ACCOUNT_TOKEN="<paste>"');
|
|
114655
|
+
ctx.output.data("");
|
|
114656
|
+
}
|
|
114657
|
+
if (!ageKey) {
|
|
114658
|
+
ctx.output.data("3. Get age key (requires OP token):");
|
|
114659
|
+
ctx.output.data(
|
|
114660
|
+
' op read "op://Support/skill-cli-age-key/private_key"'
|
|
114661
|
+
);
|
|
114662
|
+
ctx.output.data("");
|
|
114663
|
+
ctx.output.data("4. Add to ~/.zshrc:");
|
|
114664
|
+
ctx.output.data(' export SKILL_AGE_KEY="<paste>"');
|
|
114665
|
+
ctx.output.data("");
|
|
114666
|
+
}
|
|
114667
|
+
if (!isKeychainSupported()) {
|
|
114668
|
+
ctx.output.data(
|
|
114669
|
+
"Note: No keychain on this platform. Use env vars instead."
|
|
114670
|
+
);
|
|
114671
|
+
}
|
|
114672
|
+
ctx.output.data("Then run: source ~/.zshrc");
|
|
114673
|
+
});
|
|
114097
114674
|
}
|
|
114098
114675
|
|
|
114099
114676
|
// src/commands/linear/index.ts
|
|
@@ -115381,6 +115958,25 @@ var PRIORITY_EMOJI2 = {
|
|
|
115381
115958
|
3: "\u{1F7E2}",
|
|
115382
115959
|
4: "\u26AA"
|
|
115383
115960
|
};
|
|
115961
|
+
function parseRelativeTime(timeStr) {
|
|
115962
|
+
const match = timeStr.match(/^(\d+)(d|w|h|m)$/);
|
|
115963
|
+
if (!match || !match[1] || !match[2]) {
|
|
115964
|
+
throw new CLIError({
|
|
115965
|
+
userMessage: `Invalid time format: ${timeStr}`,
|
|
115966
|
+
suggestion: "Use format like 90d, 2w, 24h, or 3m"
|
|
115967
|
+
});
|
|
115968
|
+
}
|
|
115969
|
+
const value = parseInt(match[1], 10);
|
|
115970
|
+
const unit = match[2];
|
|
115971
|
+
const msMap = {
|
|
115972
|
+
h: 60 * 60 * 1e3,
|
|
115973
|
+
d: 24 * 60 * 60 * 1e3,
|
|
115974
|
+
w: 7 * 24 * 60 * 60 * 1e3,
|
|
115975
|
+
m: 30 * 24 * 60 * 60 * 1e3
|
|
115976
|
+
};
|
|
115977
|
+
const ms = value * msMap[unit];
|
|
115978
|
+
return new Date(Date.now() - ms);
|
|
115979
|
+
}
|
|
115384
115980
|
async function listIssues(ctx, options = {}) {
|
|
115385
115981
|
const limit2 = options.limit || 20;
|
|
115386
115982
|
try {
|
|
@@ -115392,6 +115988,10 @@ async function listIssues(ctx, options = {}) {
|
|
|
115392
115988
|
}
|
|
115393
115989
|
}
|
|
115394
115990
|
};
|
|
115991
|
+
if (options.olderThan) {
|
|
115992
|
+
const date = parseRelativeTime(options.olderThan);
|
|
115993
|
+
filter4.updatedAt = { lt: date };
|
|
115994
|
+
}
|
|
115395
115995
|
let teamKey;
|
|
115396
115996
|
if (options.team) {
|
|
115397
115997
|
const teams = await client.teams();
|
|
@@ -115453,28 +116053,57 @@ async function listIssues(ctx, options = {}) {
|
|
|
115453
116053
|
});
|
|
115454
116054
|
const issues = response.nodes || [];
|
|
115455
116055
|
const issuesWithDetails = await Promise.all(
|
|
115456
|
-
issues.map(async (issue) =>
|
|
115457
|
-
issue
|
|
115458
|
-
|
|
115459
|
-
|
|
115460
|
-
|
|
115461
|
-
|
|
116056
|
+
issues.map(async (issue) => {
|
|
116057
|
+
const labels = options.export ? await issue.labels() : null;
|
|
116058
|
+
const comments = options.export ? await issue.comments() : null;
|
|
116059
|
+
return {
|
|
116060
|
+
issue,
|
|
116061
|
+
state: await issue.state,
|
|
116062
|
+
assignee: await issue.assignee,
|
|
116063
|
+
team: await issue.team,
|
|
116064
|
+
labels: labels?.nodes || null,
|
|
116065
|
+
comments: comments?.nodes || null
|
|
116066
|
+
};
|
|
116067
|
+
})
|
|
115462
116068
|
);
|
|
115463
116069
|
if (ctx.format === "json") {
|
|
115464
|
-
const issueData =
|
|
115465
|
-
(
|
|
115466
|
-
|
|
115467
|
-
|
|
115468
|
-
|
|
115469
|
-
|
|
115470
|
-
|
|
115471
|
-
|
|
115472
|
-
|
|
115473
|
-
|
|
115474
|
-
|
|
115475
|
-
|
|
115476
|
-
|
|
115477
|
-
|
|
116070
|
+
const issueData = await Promise.all(
|
|
116071
|
+
issuesWithDetails.map(
|
|
116072
|
+
async ({ issue, state, assignee, team, labels, comments }) => {
|
|
116073
|
+
const baseData = {
|
|
116074
|
+
id: issue.id,
|
|
116075
|
+
identifier: issue.identifier,
|
|
116076
|
+
title: issue.title,
|
|
116077
|
+
state: state?.name || null,
|
|
116078
|
+
stateType: state?.type || null,
|
|
116079
|
+
priority: issue.priority,
|
|
116080
|
+
assignee: assignee ? {
|
|
116081
|
+
id: assignee.id,
|
|
116082
|
+
name: assignee.name,
|
|
116083
|
+
email: assignee.email
|
|
116084
|
+
} : null,
|
|
116085
|
+
team: team ? { key: team.key, name: team.name } : null,
|
|
116086
|
+
url: issue.url,
|
|
116087
|
+
createdAt: issue.createdAt,
|
|
116088
|
+
updatedAt: issue.updatedAt
|
|
116089
|
+
};
|
|
116090
|
+
if (options.export) {
|
|
116091
|
+
return {
|
|
116092
|
+
...baseData,
|
|
116093
|
+
description: issue.description,
|
|
116094
|
+
labels: labels ? labels.map((l) => l.name) : [],
|
|
116095
|
+
comments: comments ? await Promise.all(
|
|
116096
|
+
comments.map(async (c) => ({
|
|
116097
|
+
body: c.body,
|
|
116098
|
+
user: (await c.user)?.name || "Unknown",
|
|
116099
|
+
createdAt: c.createdAt
|
|
116100
|
+
}))
|
|
116101
|
+
) : []
|
|
116102
|
+
};
|
|
116103
|
+
}
|
|
116104
|
+
return baseData;
|
|
116105
|
+
}
|
|
116106
|
+
)
|
|
115478
116107
|
);
|
|
115479
116108
|
ctx.output.data(
|
|
115480
116109
|
JSON.stringify(
|
|
@@ -115522,7 +116151,14 @@ async function listIssues(ctx, options = {}) {
|
|
|
115522
116151
|
ctx.output.data("");
|
|
115523
116152
|
return;
|
|
115524
116153
|
}
|
|
115525
|
-
for (const {
|
|
116154
|
+
for (const {
|
|
116155
|
+
issue,
|
|
116156
|
+
state,
|
|
116157
|
+
assignee,
|
|
116158
|
+
team,
|
|
116159
|
+
labels,
|
|
116160
|
+
comments
|
|
116161
|
+
} of issuesWithDetails) {
|
|
115526
116162
|
const emoji = PRIORITY_EMOJI2[issue.priority] || "\u26AA";
|
|
115527
116163
|
const assigneeName = assignee ? `@${assignee.name}` : "";
|
|
115528
116164
|
const teamBadge = team ? `[${team.key}]` : "";
|
|
@@ -115533,6 +116169,19 @@ async function listIssues(ctx, options = {}) {
|
|
|
115533
116169
|
ctx.output.data(
|
|
115534
116170
|
` Status: ${state?.name || "unknown"}${assigneeName ? ` | Assignee: ${assigneeName}` : ""}`
|
|
115535
116171
|
);
|
|
116172
|
+
if (options.export) {
|
|
116173
|
+
if (issue.description) {
|
|
116174
|
+
ctx.output.data(` Description: ${issue.description}`);
|
|
116175
|
+
}
|
|
116176
|
+
if (labels && labels.length > 0) {
|
|
116177
|
+
ctx.output.data(
|
|
116178
|
+
` Labels: ${labels.map((l) => l.name).join(", ")}`
|
|
116179
|
+
);
|
|
116180
|
+
}
|
|
116181
|
+
if (comments && comments.length > 0) {
|
|
116182
|
+
ctx.output.data(` Comments: ${comments.length}`);
|
|
116183
|
+
}
|
|
116184
|
+
}
|
|
115536
116185
|
}
|
|
115537
116186
|
ctx.output.data("");
|
|
115538
116187
|
ctx.output.data(" Use `skill linear issue <ID> --json` for full details.");
|
|
@@ -115561,26 +116210,31 @@ async function listMyIssues(ctx, options = {}) {
|
|
|
115561
116210
|
const limit2 = options.limit || 20;
|
|
115562
116211
|
try {
|
|
115563
116212
|
const client = getLinearClient();
|
|
115564
|
-
const viewer = await
|
|
115565
|
-
|
|
115566
|
-
|
|
115567
|
-
|
|
115568
|
-
|
|
115569
|
-
|
|
116213
|
+
const { viewer, issues } = await withSpinner(
|
|
116214
|
+
"Loading issues...",
|
|
116215
|
+
async () => {
|
|
116216
|
+
const viewer2 = await client.viewer;
|
|
116217
|
+
const filter4 = {
|
|
116218
|
+
assignee: { id: { eq: viewer2.id } },
|
|
116219
|
+
state: {
|
|
116220
|
+
type: {
|
|
116221
|
+
nin: ["canceled", "completed"]
|
|
116222
|
+
}
|
|
116223
|
+
}
|
|
116224
|
+
};
|
|
116225
|
+
if (options.state) {
|
|
116226
|
+
filter4.state = {
|
|
116227
|
+
...filter4.state || {},
|
|
116228
|
+
name: { eqIgnoreCase: options.state }
|
|
116229
|
+
};
|
|
115570
116230
|
}
|
|
116231
|
+
const response = await client.issues({
|
|
116232
|
+
first: limit2,
|
|
116233
|
+
filter: filter4
|
|
116234
|
+
});
|
|
116235
|
+
return { viewer: viewer2, issues: response.nodes || [] };
|
|
115571
116236
|
}
|
|
115572
|
-
|
|
115573
|
-
if (options.state) {
|
|
115574
|
-
filter4.state = {
|
|
115575
|
-
...filter4.state || {},
|
|
115576
|
-
name: { eqIgnoreCase: options.state }
|
|
115577
|
-
};
|
|
115578
|
-
}
|
|
115579
|
-
const response = await client.issues({
|
|
115580
|
-
first: limit2,
|
|
115581
|
-
filter: filter4
|
|
115582
|
-
});
|
|
115583
|
-
const issues = response.nodes || [];
|
|
116237
|
+
);
|
|
115584
116238
|
const issuesWithDetails = await Promise.all(
|
|
115585
116239
|
issues.map(async (issue) => ({
|
|
115586
116240
|
issue,
|
|
@@ -115759,9 +116413,12 @@ async function searchIssues(ctx, query, options = {}) {
|
|
|
115759
116413
|
const limit2 = options.limit || 20;
|
|
115760
116414
|
try {
|
|
115761
116415
|
const client = getLinearClient();
|
|
115762
|
-
const response = await
|
|
115763
|
-
|
|
115764
|
-
|
|
116416
|
+
const response = await withSpinner(
|
|
116417
|
+
"Searching issues...",
|
|
116418
|
+
() => client.searchIssues(query.trim(), {
|
|
116419
|
+
first: limit2
|
|
116420
|
+
})
|
|
116421
|
+
);
|
|
115765
116422
|
const issues = response.nodes || [];
|
|
115766
116423
|
const issuesWithDetails = await Promise.all(
|
|
115767
116424
|
issues.map(async (issue) => ({
|
|
@@ -116050,7 +116707,7 @@ init_esm_shims();
|
|
|
116050
116707
|
async function listTeams(ctx, options = {}) {
|
|
116051
116708
|
try {
|
|
116052
116709
|
const client = getLinearClient();
|
|
116053
|
-
const response = await client.teams();
|
|
116710
|
+
const response = await withSpinner("Loading teams...", () => client.teams());
|
|
116054
116711
|
const teams = response.nodes || [];
|
|
116055
116712
|
if (ctx.format === "json") {
|
|
116056
116713
|
ctx.output.data(
|
|
@@ -116318,6 +116975,13 @@ Quick start:
|
|
|
116318
116975
|
skill linear create "Title" Create issue
|
|
116319
116976
|
skill linear search "query" Search issues
|
|
116320
116977
|
|
|
116978
|
+
Bulk queries:
|
|
116979
|
+
skill linear issues --older-than 90d Stale issues
|
|
116980
|
+
skill linear issues --older-than 2w --export Full data export
|
|
116981
|
+
|
|
116982
|
+
Environment:
|
|
116983
|
+
LINEAR_API_KEY required. Run 'skill doctor' to check.
|
|
116984
|
+
|
|
116321
116985
|
All commands support --json for machine-readable output.
|
|
116322
116986
|
|
|
116323
116987
|
\u26A0\uFE0F Write operations require personal LINEAR_API_KEY (run 'skill keys add').`
|
|
@@ -116330,8 +116994,10 @@ Examples:
|
|
|
116330
116994
|
skill linear issues --team ENG Filter by team
|
|
116331
116995
|
skill linear issues --state "In Progress" Filter by state
|
|
116332
116996
|
skill linear issues --assignee me Your issues
|
|
116333
|
-
skill linear issues --priority 0 Urgent only
|
|
116334
|
-
|
|
116997
|
+
skill linear issues --priority 0 Urgent only
|
|
116998
|
+
skill linear issues --older-than 90d Stale issues (90+ days)
|
|
116999
|
+
skill linear issues --older-than 2w --export Full export`
|
|
117000
|
+
).option("--limit <number>", "Maximum results (default: 20)", "20").option("--team <key>", "Filter by team key (e.g., ENG)").option("--state <name>", "Filter by state name").option("--assignee <email>", 'Filter by assignee (or "me")').option("--project <name>", "Filter by project name").option("--priority <0-4>", "Filter by priority (0=urgent)").option("--older-than <time>", "Filter by last update (90d, 2w, 24h, 3m)").option("--export", "Include full details (description, labels, comments)").option("--json", "Output as JSON with HATEOAS links").action(async (options, command) => {
|
|
116335
117001
|
const ctx = await contextFromCommand2(command, options);
|
|
116336
117002
|
await listIssues(ctx, {
|
|
116337
117003
|
limit: parseInt(options.limit || "20", 10),
|
|
@@ -116339,7 +117005,9 @@ Examples:
|
|
|
116339
117005
|
state: options.state,
|
|
116340
117006
|
assignee: options.assignee,
|
|
116341
117007
|
project: options.project,
|
|
116342
|
-
priority: options.priority !== void 0 ? parseInt(options.priority, 10) : void 0
|
|
117008
|
+
priority: options.priority !== void 0 ? parseInt(options.priority, 10) : void 0,
|
|
117009
|
+
olderThan: options.olderThan,
|
|
117010
|
+
export: options.export
|
|
116343
117011
|
});
|
|
116344
117012
|
});
|
|
116345
117013
|
linear.command("my").description(
|
|
@@ -116586,6 +117254,101 @@ Examples:
|
|
|
116586
117254
|
});
|
|
116587
117255
|
}
|
|
116588
117256
|
|
|
117257
|
+
// src/commands/list.ts
|
|
117258
|
+
init_esm_shims();
|
|
117259
|
+
import { existsSync as existsSync16, readFileSync as readFileSync13, readdirSync, statSync } from "fs";
|
|
117260
|
+
import { join as join14 } from "path";
|
|
117261
|
+
function discoverSkills(skillsDir) {
|
|
117262
|
+
if (!existsSync16(skillsDir)) {
|
|
117263
|
+
return [];
|
|
117264
|
+
}
|
|
117265
|
+
const skills = [];
|
|
117266
|
+
try {
|
|
117267
|
+
const entries = readdirSync(skillsDir);
|
|
117268
|
+
for (const entry of entries) {
|
|
117269
|
+
const entryPath = join14(skillsDir, entry);
|
|
117270
|
+
const stat = statSync(entryPath);
|
|
117271
|
+
if (!stat.isDirectory()) continue;
|
|
117272
|
+
const skillPath = join14(entryPath, "SKILL.md");
|
|
117273
|
+
if (!existsSync16(skillPath)) continue;
|
|
117274
|
+
const content = readFileSync13(skillPath, "utf8");
|
|
117275
|
+
const description = extractDescription(content);
|
|
117276
|
+
skills.push({
|
|
117277
|
+
name: entry,
|
|
117278
|
+
description,
|
|
117279
|
+
path: skillPath
|
|
117280
|
+
});
|
|
117281
|
+
}
|
|
117282
|
+
} catch {
|
|
117283
|
+
return [];
|
|
117284
|
+
}
|
|
117285
|
+
return skills.sort((a, b) => a.name.localeCompare(b.name));
|
|
117286
|
+
}
|
|
117287
|
+
function extractDescription(markdown) {
|
|
117288
|
+
const lines = markdown.split("\n");
|
|
117289
|
+
let inFrontmatter = false;
|
|
117290
|
+
let foundHeading = false;
|
|
117291
|
+
const descriptionLines = [];
|
|
117292
|
+
for (const line of lines) {
|
|
117293
|
+
const trimmed = line.trim();
|
|
117294
|
+
if (trimmed === "---") {
|
|
117295
|
+
if (!inFrontmatter && !foundHeading) {
|
|
117296
|
+
inFrontmatter = true;
|
|
117297
|
+
continue;
|
|
117298
|
+
} else if (inFrontmatter) {
|
|
117299
|
+
inFrontmatter = false;
|
|
117300
|
+
continue;
|
|
117301
|
+
}
|
|
117302
|
+
}
|
|
117303
|
+
if (inFrontmatter) continue;
|
|
117304
|
+
if (trimmed.startsWith("# ")) {
|
|
117305
|
+
foundHeading = true;
|
|
117306
|
+
continue;
|
|
117307
|
+
}
|
|
117308
|
+
if (foundHeading && trimmed.startsWith("#")) {
|
|
117309
|
+
break;
|
|
117310
|
+
}
|
|
117311
|
+
if (foundHeading) {
|
|
117312
|
+
if (trimmed === "") {
|
|
117313
|
+
if (descriptionLines.length > 0) {
|
|
117314
|
+
break;
|
|
117315
|
+
}
|
|
117316
|
+
continue;
|
|
117317
|
+
}
|
|
117318
|
+
descriptionLines.push(trimmed);
|
|
117319
|
+
}
|
|
117320
|
+
}
|
|
117321
|
+
return descriptionLines.join(" ").trim();
|
|
117322
|
+
}
|
|
117323
|
+
async function listAction(options, command) {
|
|
117324
|
+
const ctx = await createContext({
|
|
117325
|
+
format: options.json ? "json" : command.optsWithGlobals().format,
|
|
117326
|
+
verbose: command.optsWithGlobals().verbose,
|
|
117327
|
+
quiet: command.optsWithGlobals().quiet
|
|
117328
|
+
});
|
|
117329
|
+
const skillsDir = join14(process.cwd(), ".claude", "skills");
|
|
117330
|
+
const skills = discoverSkills(skillsDir);
|
|
117331
|
+
if (options.json) {
|
|
117332
|
+
ctx.output.data({ skills });
|
|
117333
|
+
return;
|
|
117334
|
+
}
|
|
117335
|
+
if (skills.length === 0) {
|
|
117336
|
+
ctx.output.message("No skills found in .claude/skills/");
|
|
117337
|
+
return;
|
|
117338
|
+
}
|
|
117339
|
+
ctx.output.data(`
|
|
117340
|
+
\u{1F4DA} Available Skills (${skills.length})`);
|
|
117341
|
+
ctx.output.data("\u2500".repeat(80));
|
|
117342
|
+
const rows = skills.map((skill) => ({
|
|
117343
|
+
Name: skill.name,
|
|
117344
|
+
Description: skill.description || "(no description)"
|
|
117345
|
+
}));
|
|
117346
|
+
ctx.output.table(rows);
|
|
117347
|
+
}
|
|
117348
|
+
function registerListCommand(program3) {
|
|
117349
|
+
program3.command("list").description("List available CLI skills for programmatic discovery").option("--json", "Output as JSON").action(listAction);
|
|
117350
|
+
}
|
|
117351
|
+
|
|
116589
117352
|
// src/commands/memory/index.ts
|
|
116590
117353
|
init_esm_shims();
|
|
116591
117354
|
|
|
@@ -117604,7 +118367,7 @@ var handlePipelineError = (ctx, error, message, suggestion = "Verify inputs and
|
|
|
117604
118367
|
async function runPipelineCommand(ctx, opts) {
|
|
117605
118368
|
const outputJson = opts.json === true || ctx.format === "json";
|
|
117606
118369
|
try {
|
|
117607
|
-
const { runPipeline: runPipeline2 } = await import("./pipeline-
|
|
118370
|
+
const { runPipeline: runPipeline2 } = await import("./pipeline-TMFQSA7X.js");
|
|
117608
118371
|
const result = await runPipeline2({
|
|
117609
118372
|
message: {
|
|
117610
118373
|
subject: opts.subject,
|
|
@@ -117715,16 +118478,16 @@ function registerPipelineCommands(program3) {
|
|
|
117715
118478
|
// src/commands/plugin-sync.ts
|
|
117716
118479
|
init_esm_shims();
|
|
117717
118480
|
import { homedir as homedir3 } from "os";
|
|
117718
|
-
import { dirname as dirname3, join as
|
|
118481
|
+
import { dirname as dirname3, join as join15, resolve as resolve6 } from "path";
|
|
117719
118482
|
import { fileURLToPath } from "url";
|
|
117720
118483
|
var PLUGIN_SOURCE_DIR = resolve6(
|
|
117721
118484
|
dirname3(fileURLToPath(import.meta.url)),
|
|
117722
118485
|
"../../plugin"
|
|
117723
118486
|
);
|
|
117724
|
-
var PLUGIN_MANIFEST_RELATIVE =
|
|
118487
|
+
var PLUGIN_MANIFEST_RELATIVE = join15(".claude-plugin", "plugin.json");
|
|
117725
118488
|
var resolveTargetDir = (global2) => {
|
|
117726
|
-
const base =
|
|
117727
|
-
return
|
|
118489
|
+
const base = join15(homedir3(), ".claude", global2 ? "skills" : "plugins");
|
|
118490
|
+
return join15(base, "skill-cli");
|
|
117728
118491
|
};
|
|
117729
118492
|
var readManifest = async (path) => {
|
|
117730
118493
|
const manifest = await readJson(path);
|
|
@@ -117753,7 +118516,7 @@ var writeResult4 = (ctx, payload) => {
|
|
|
117753
118516
|
};
|
|
117754
118517
|
async function executePluginSync(ctx, options) {
|
|
117755
118518
|
try {
|
|
117756
|
-
const sourceManifestPath =
|
|
118519
|
+
const sourceManifestPath = join15(PLUGIN_SOURCE_DIR, PLUGIN_MANIFEST_RELATIVE);
|
|
117757
118520
|
const sourceExists = await pathExists(sourceManifestPath);
|
|
117758
118521
|
if (!sourceExists) {
|
|
117759
118522
|
throw new CLIError({
|
|
@@ -117763,7 +118526,7 @@ async function executePluginSync(ctx, options) {
|
|
|
117763
118526
|
}
|
|
117764
118527
|
const sourceManifest = await readManifest(sourceManifestPath);
|
|
117765
118528
|
const targetDir = resolveTargetDir(options.global);
|
|
117766
|
-
const targetManifestPath =
|
|
118529
|
+
const targetManifestPath = join15(targetDir, PLUGIN_MANIFEST_RELATIVE);
|
|
117767
118530
|
const targetExists = await pathExists(targetManifestPath);
|
|
117768
118531
|
if (targetExists && !options.force) {
|
|
117769
118532
|
const targetManifest = await readManifest(targetManifestPath);
|
|
@@ -119006,7 +119769,7 @@ init_esm_shims();
|
|
|
119006
119769
|
import { spawn } from "child_process";
|
|
119007
119770
|
import { writeFile as writeFile7 } from "fs/promises";
|
|
119008
119771
|
import { homedir as homedir4 } from "os";
|
|
119009
|
-
import { dirname as dirname4, join as
|
|
119772
|
+
import { dirname as dirname4, join as join16 } from "path";
|
|
119010
119773
|
var CONFIG_DIR_NAME = "skill-cli";
|
|
119011
119774
|
var AUTO_UPDATE_STATE_FILE = "auto-update.json";
|
|
119012
119775
|
var DEFAULT_PACKAGE = "@skillrecordings/cli";
|
|
@@ -119018,7 +119781,7 @@ var AutoUpdateStore = class {
|
|
|
119018
119781
|
now;
|
|
119019
119782
|
constructor(options = {}) {
|
|
119020
119783
|
const configDir = resolveConfigDir(options.configDir);
|
|
119021
|
-
this.filePath =
|
|
119784
|
+
this.filePath = join16(configDir, AUTO_UPDATE_STATE_FILE);
|
|
119022
119785
|
this.now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
119023
119786
|
}
|
|
119024
119787
|
getNow() {
|
|
@@ -119046,9 +119809,9 @@ function resolveConfigDir(configDir) {
|
|
|
119046
119809
|
if (configDir) return configDir;
|
|
119047
119810
|
const xdgConfigHome = process.env.XDG_CONFIG_HOME;
|
|
119048
119811
|
if (xdgConfigHome && xdgConfigHome.trim() !== "") {
|
|
119049
|
-
return
|
|
119812
|
+
return join16(xdgConfigHome, CONFIG_DIR_NAME);
|
|
119050
119813
|
}
|
|
119051
|
-
return
|
|
119814
|
+
return join16(homedir4(), ".config", CONFIG_DIR_NAME);
|
|
119052
119815
|
}
|
|
119053
119816
|
function isAutoUpdateState(value) {
|
|
119054
119817
|
if (!value || typeof value !== "object") return false;
|
|
@@ -119220,9 +119983,6 @@ init_esm_shims();
|
|
|
119220
119983
|
var DEFAULT_MAX_HINTS = 2;
|
|
119221
119984
|
var getCommandCount = (state, command) => state.commands[command]?.count ?? 0;
|
|
119222
119985
|
var hasCommand = (state, command) => getCommandCount(state, command) > 0;
|
|
119223
|
-
var hasCommandPrefix = (state, prefix) => Object.entries(state.commands).some(
|
|
119224
|
-
([name, entry]) => name.startsWith(prefix) && entry.count > 0
|
|
119225
|
-
);
|
|
119226
119986
|
var hasMilestone = (state, milestone) => state.milestones[milestone]?.achieved ?? false;
|
|
119227
119987
|
var shouldSuppressHints = (context) => context.quiet === true || context.format === "json";
|
|
119228
119988
|
var resolveMaxHints = (context) => context.maxHints ?? DEFAULT_MAX_HINTS;
|
|
@@ -119231,79 +119991,76 @@ var toHint = (rule) => ({
|
|
|
119231
119991
|
message: rule.message,
|
|
119232
119992
|
audience: rule.audience
|
|
119233
119993
|
});
|
|
119994
|
+
var isCommandGroup = (command, group) => command === group || command.startsWith(`${group}.`);
|
|
119234
119995
|
var DEFAULT_HINT_RULES = [
|
|
119996
|
+
// Front contextual hints
|
|
119235
119997
|
{
|
|
119236
|
-
id: "
|
|
119237
|
-
audience: "
|
|
119238
|
-
|
|
119239
|
-
|
|
119240
|
-
|
|
119241
|
-
|
|
119242
|
-
{
|
|
119243
|
-
id: "onboarding.auth",
|
|
119244
|
-
audience: "onboarding",
|
|
119245
|
-
message: "Set up your own API keys with `skill keys`.",
|
|
119246
|
-
showWhen: (state) => state.totalRuns >= 1 && !hasMilestone(state, "auth_configured"),
|
|
119247
|
-
retireWhen: (state) => hasMilestone(state, "auth_configured")
|
|
119248
|
-
},
|
|
119249
|
-
{
|
|
119250
|
-
id: "discovery.health",
|
|
119251
|
-
audience: "discovery",
|
|
119252
|
-
message: "Check integrations fast with `skill health <app-slug>`.",
|
|
119253
|
-
showWhen: (state) => state.totalRuns >= 2 && !hasCommand(state, "health"),
|
|
119254
|
-
retireWhen: (state) => hasCommand(state, "health")
|
|
119998
|
+
id: "context.front.triage",
|
|
119999
|
+
audience: "contextual",
|
|
120000
|
+
postRun: true,
|
|
120001
|
+
message: "Tip: `skill front triage` to auto-categorize unassigned threads.",
|
|
120002
|
+
showWhen: (state, context) => context.command === "front.inbox" && !hasCommand(state, "front.triage"),
|
|
120003
|
+
retireWhen: (state) => hasCommand(state, "front.triage")
|
|
119255
120004
|
},
|
|
119256
120005
|
{
|
|
119257
|
-
id: "
|
|
119258
|
-
audience: "
|
|
119259
|
-
|
|
119260
|
-
|
|
119261
|
-
|
|
120006
|
+
id: "context.front.conversation",
|
|
120007
|
+
audience: "contextual",
|
|
120008
|
+
postRun: true,
|
|
120009
|
+
message: "Tip: `skill front conversation <id> -m` shows the full thread.",
|
|
120010
|
+
showWhen: (state, context) => context.command === "front.message" && !hasCommand(state, "front.conversation"),
|
|
120011
|
+
retireWhen: (state) => hasCommand(state, "front.conversation")
|
|
119262
120012
|
},
|
|
119263
120013
|
{
|
|
119264
|
-
id: "
|
|
119265
|
-
audience: "
|
|
119266
|
-
|
|
119267
|
-
|
|
119268
|
-
|
|
120014
|
+
id: "context.front.reply",
|
|
120015
|
+
audience: "contextual",
|
|
120016
|
+
postRun: true,
|
|
120017
|
+
message: "Tip: `skill front reply <id>` to draft a response.",
|
|
120018
|
+
showWhen: (state, context) => context.command === "front.conversation" && !hasCommand(state, "front.reply"),
|
|
120019
|
+
retireWhen: (state) => hasCommand(state, "front.reply")
|
|
119269
120020
|
},
|
|
120021
|
+
// Inngest contextual hints
|
|
119270
120022
|
{
|
|
119271
|
-
id: "
|
|
119272
|
-
audience: "
|
|
119273
|
-
|
|
119274
|
-
|
|
119275
|
-
|
|
120023
|
+
id: "context.inngest.run",
|
|
120024
|
+
audience: "contextual",
|
|
120025
|
+
postRun: true,
|
|
120026
|
+
message: "Tip: `skill inngest run <id>` to inspect a specific run.",
|
|
120027
|
+
showWhen: (state, context) => (context.command === "inngest.failures" || context.command === "inngest.runs") && !hasCommand(state, "inngest.run"),
|
|
120028
|
+
retireWhen: (state) => hasCommand(state, "inngest.run")
|
|
119276
120029
|
},
|
|
119277
120030
|
{
|
|
119278
|
-
id: "
|
|
119279
|
-
audience: "
|
|
119280
|
-
|
|
119281
|
-
|
|
119282
|
-
|
|
120031
|
+
id: "context.inngest.trace",
|
|
120032
|
+
audience: "contextual",
|
|
120033
|
+
postRun: true,
|
|
120034
|
+
message: "Tip: `skill inngest trace <run-id>` for full workflow trace.",
|
|
120035
|
+
showWhen: (state, context) => context.command === "inngest.run" && !hasCommand(state, "inngest.trace"),
|
|
120036
|
+
retireWhen: (state) => hasCommand(state, "inngest.trace")
|
|
119283
120037
|
},
|
|
120038
|
+
// Linear contextual hints
|
|
119284
120039
|
{
|
|
119285
|
-
id: "context.
|
|
120040
|
+
id: "context.linear.my",
|
|
119286
120041
|
audience: "contextual",
|
|
119287
120042
|
postRun: true,
|
|
119288
|
-
message: "Tip: `skill
|
|
119289
|
-
showWhen: (state, context) => context.command
|
|
119290
|
-
retireWhen: (state) => hasCommand(state, "
|
|
120043
|
+
message: "Tip: `skill linear my` to see your assigned issues.",
|
|
120044
|
+
showWhen: (state, context) => isCommandGroup(context.command, "linear") && context.command !== "linear.my" && !hasCommand(state, "linear.my"),
|
|
120045
|
+
retireWhen: (state) => hasCommand(state, "linear.my")
|
|
119291
120046
|
},
|
|
120047
|
+
// Axiom contextual hints
|
|
119292
120048
|
{
|
|
119293
|
-
id: "context.
|
|
120049
|
+
id: "context.axiom.errors",
|
|
119294
120050
|
audience: "contextual",
|
|
119295
120051
|
postRun: true,
|
|
119296
|
-
message: "Tip: `skill
|
|
119297
|
-
showWhen: (state, context) => context.command === "
|
|
119298
|
-
retireWhen: (state) => hasCommand(state, "
|
|
120052
|
+
message: "Tip: `skill axiom errors --since 1h` to see recent errors.",
|
|
120053
|
+
showWhen: (state, context) => context.command === "axiom.query" && !hasCommand(state, "axiom.errors"),
|
|
120054
|
+
retireWhen: (state) => hasCommand(state, "axiom.errors")
|
|
119299
120055
|
},
|
|
120056
|
+
// Keys hint - only when auth issues are likely
|
|
119300
120057
|
{
|
|
119301
|
-
id: "context.
|
|
120058
|
+
id: "context.keys",
|
|
119302
120059
|
audience: "contextual",
|
|
119303
120060
|
postRun: true,
|
|
119304
|
-
message: "Tip:
|
|
119305
|
-
showWhen: (state, context) => context.command === "
|
|
119306
|
-
retireWhen: (state) => hasCommand(state, "
|
|
120061
|
+
message: "Tip: `skill keys setup` to configure keychain integration.",
|
|
120062
|
+
showWhen: (state, context) => context.command === "auth.status" && !hasCommand(state, "keys.setup") && !hasMilestone(state, "auth_configured"),
|
|
120063
|
+
retireWhen: (state) => hasCommand(state, "keys.setup") || hasMilestone(state, "auth_configured")
|
|
119307
120064
|
}
|
|
119308
120065
|
];
|
|
119309
120066
|
var HintEngine = class {
|
|
@@ -119351,13 +120108,13 @@ var writeHints = (hints, stderr) => {
|
|
|
119351
120108
|
init_esm_shims();
|
|
119352
120109
|
import { lstat, readlink, symlink } from "fs/promises";
|
|
119353
120110
|
import { homedir as homedir5 } from "os";
|
|
119354
|
-
import { dirname as dirname5, join as
|
|
120111
|
+
import { dirname as dirname5, join as join17, resolve as resolve7 } from "path";
|
|
119355
120112
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
119356
120113
|
var SKILL_SOURCE_DIR = resolve7(
|
|
119357
120114
|
dirname5(fileURLToPath2(import.meta.url)),
|
|
119358
120115
|
"../../../../.claude/skills/skill-cli"
|
|
119359
120116
|
);
|
|
119360
|
-
var SKILL_TARGET_DIR =
|
|
120117
|
+
var SKILL_TARGET_DIR = join17(homedir5(), ".claude", "skills", "skill-cli");
|
|
119361
120118
|
async function autoLinkSkill() {
|
|
119362
120119
|
const source = SKILL_SOURCE_DIR;
|
|
119363
120120
|
const target = SKILL_TARGET_DIR;
|
|
@@ -119461,16 +120218,16 @@ async function sendTelemetryEvent(event) {
|
|
|
119461
120218
|
init_esm_shims();
|
|
119462
120219
|
import { writeFile as writeFile8 } from "fs/promises";
|
|
119463
120220
|
import { homedir as homedir6 } from "os";
|
|
119464
|
-
import { dirname as dirname6, join as
|
|
120221
|
+
import { dirname as dirname6, join as join18 } from "path";
|
|
119465
120222
|
var CONFIG_DIR_NAME2 = "skill-cli";
|
|
119466
120223
|
var USAGE_FILE_NAME = "usage.json";
|
|
119467
120224
|
function resolveConfigDir2(configDir) {
|
|
119468
120225
|
if (configDir) return configDir;
|
|
119469
120226
|
const xdgConfigHome = process.env.XDG_CONFIG_HOME;
|
|
119470
120227
|
if (xdgConfigHome && xdgConfigHome.trim() !== "") {
|
|
119471
|
-
return
|
|
120228
|
+
return join18(xdgConfigHome, CONFIG_DIR_NAME2);
|
|
119472
120229
|
}
|
|
119473
|
-
return
|
|
120230
|
+
return join18(homedir6(), ".config", CONFIG_DIR_NAME2);
|
|
119474
120231
|
}
|
|
119475
120232
|
function createDefaultState(now) {
|
|
119476
120233
|
return {
|
|
@@ -119508,7 +120265,7 @@ var UsageTracker = class {
|
|
|
119508
120265
|
statePromise;
|
|
119509
120266
|
constructor(options = {}) {
|
|
119510
120267
|
const configDir = resolveConfigDir2(options.configDir);
|
|
119511
|
-
this.filePath =
|
|
120268
|
+
this.filePath = join18(configDir, USAGE_FILE_NAME);
|
|
119512
120269
|
this.now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
119513
120270
|
}
|
|
119514
120271
|
async loadState() {
|
|
@@ -120087,8 +120844,8 @@ if (!envLoaded && !process.env.DATABASE_URL) {
|
|
|
120087
120844
|
process.env.SKIP_ENV_VALIDATION = "1";
|
|
120088
120845
|
}
|
|
120089
120846
|
var runtimeTarget = `bun-${process.platform}-${process.arch}`;
|
|
120090
|
-
var buildVersion = "0.
|
|
120091
|
-
var buildCommit = "
|
|
120847
|
+
var buildVersion = "0.18.0".length > 0 ? "0.18.0" : "0.0.0-dev";
|
|
120848
|
+
var buildCommit = "8d98b14".length > 0 ? "8d98b14" : "dev";
|
|
120092
120849
|
var buildTarget = "node".length > 0 ? "node" : runtimeTarget;
|
|
120093
120850
|
var isDevBuild = buildVersion.includes("dev") || buildCommit === "dev";
|
|
120094
120851
|
var versionLabel = `skill v${buildVersion} (${buildCommit}) ${buildTarget}`;
|
|
@@ -120102,7 +120859,6 @@ var usageState = await (async () => {
|
|
|
120102
120859
|
return null;
|
|
120103
120860
|
}
|
|
120104
120861
|
})();
|
|
120105
|
-
var hintCounts = /* @__PURE__ */ new WeakMap();
|
|
120106
120862
|
var commandStartTimes = /* @__PURE__ */ new WeakMap();
|
|
120107
120863
|
var resolveCommandName = (command) => {
|
|
120108
120864
|
const names = [];
|
|
@@ -120158,16 +120914,6 @@ program2.hook("preAction", (thisCommand, actionCommand) => {
|
|
|
120158
120914
|
program2.hook("preAction", (_thisCommand, actionCommand) => {
|
|
120159
120915
|
commandStartTimes.set(actionCommand, Date.now());
|
|
120160
120916
|
});
|
|
120161
|
-
program2.hook("preAction", async (_thisCommand, actionCommand) => {
|
|
120162
|
-
try {
|
|
120163
|
-
const context = resolveHintContext(actionCommand);
|
|
120164
|
-
const state = await usageTracker.getUsage();
|
|
120165
|
-
const hints = hintEngine.getHints(state, context);
|
|
120166
|
-
writeHints(hints, process.stderr);
|
|
120167
|
-
hintCounts.set(actionCommand, hints.length);
|
|
120168
|
-
} catch {
|
|
120169
|
-
}
|
|
120170
|
-
});
|
|
120171
120917
|
program2.hook("postAction", async (_thisCommand, actionCommand) => {
|
|
120172
120918
|
try {
|
|
120173
120919
|
const context = resolveHintContext(actionCommand);
|
|
@@ -120176,11 +120922,7 @@ program2.hook("postAction", async (_thisCommand, actionCommand) => {
|
|
|
120176
120922
|
for (const milestone of milestones) {
|
|
120177
120923
|
await usageTracker.setMilestone(milestone);
|
|
120178
120924
|
}
|
|
120179
|
-
const
|
|
120180
|
-
const postHint = hintEngine.getPostRunHint(state, {
|
|
120181
|
-
...context,
|
|
120182
|
-
previouslyShown
|
|
120183
|
-
});
|
|
120925
|
+
const postHint = hintEngine.getPostRunHint(state, context);
|
|
120184
120926
|
if (postHint) writeHints([postHint], process.stderr);
|
|
120185
120927
|
} catch {
|
|
120186
120928
|
}
|
|
@@ -120308,6 +121050,8 @@ registerKbCommands(program2);
|
|
|
120308
121050
|
registerAuthCommands(program2, usageState);
|
|
120309
121051
|
registerConfigCommands(program2);
|
|
120310
121052
|
registerKeysCommands(program2);
|
|
121053
|
+
registerDoctorCommand(program2);
|
|
121054
|
+
registerListCommand(program2);
|
|
120311
121055
|
registerPluginSyncCommand(program2);
|
|
120312
121056
|
program2.command("mcp").description(
|
|
120313
121057
|
"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)"
|