@simonfestl/husky-cli 1.21.1 ā 1.23.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/commands/auth.js +8 -2
- package/dist/commands/brain.js +124 -0
- package/dist/lib/api-client.js +7 -0
- package/package.json +1 -1
package/dist/commands/auth.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
2
|
import { getConfig, setSessionConfig, clearSessionConfig, getSessionConfig, fetchAndCacheRole } from "./config.js";
|
|
3
3
|
import { getPermissions, clearPermissionsCache, getCacheStatus, hasPermission, canAccessKnowledgeBase } from "../lib/permissions-cache.js";
|
|
4
|
+
import { apiRequest as hybridApiRequest } from "../lib/api-client.js";
|
|
4
5
|
const API_KEY_ROLES = [
|
|
5
6
|
"admin", "supervisor", "worker", "reviewer", "support",
|
|
6
7
|
"purchasing", "ops", "e2e_agent", "pr_agent"
|
|
@@ -164,7 +165,7 @@ authCommand
|
|
|
164
165
|
.option("--json", "Output as JSON")
|
|
165
166
|
.action(async (options) => {
|
|
166
167
|
try {
|
|
167
|
-
const data = await
|
|
168
|
+
const data = await hybridApiRequest("/api/auth/whoami");
|
|
168
169
|
if (options.json) {
|
|
169
170
|
console.log(JSON.stringify(data, null, 2));
|
|
170
171
|
return;
|
|
@@ -172,7 +173,12 @@ authCommand
|
|
|
172
173
|
console.log("\nš Authentication Info");
|
|
173
174
|
console.log("ā".repeat(40));
|
|
174
175
|
console.log(`Role: ${data.role}`);
|
|
175
|
-
|
|
176
|
+
if (data.keyId) {
|
|
177
|
+
console.log(`Key ID: ${data.keyId}`);
|
|
178
|
+
}
|
|
179
|
+
if (data.agent) {
|
|
180
|
+
console.log(`Agent: ${data.agent}`);
|
|
181
|
+
}
|
|
176
182
|
console.log(`Source: ${data.source}`);
|
|
177
183
|
if (data.scopes && data.scopes.length > 0) {
|
|
178
184
|
console.log(`Scopes: ${data.scopes.join(", ")}`);
|
package/dist/commands/brain.js
CHANGED
|
@@ -539,6 +539,130 @@ brainCommand
|
|
|
539
539
|
}
|
|
540
540
|
});
|
|
541
541
|
// ============================================================================
|
|
542
|
+
// Auto-Brain: Hook Integration Commands
|
|
543
|
+
// ============================================================================
|
|
544
|
+
brainCommand
|
|
545
|
+
.command("auto-recall <prompt>")
|
|
546
|
+
.description("Automatically search brain for relevant memories based on user prompt (for hook integration)")
|
|
547
|
+
.option("-a, --agent <id>", "Agent ID", DEFAULT_AGENT)
|
|
548
|
+
.option("-l, --limit <num>", "Max results", "3")
|
|
549
|
+
.option("-m, --min-score <score>", "Minimum similarity score (0-1)", "0.6")
|
|
550
|
+
.option("--agent-type <type>", `Agent type for database selection (${AGENT_TYPES.join(", ")})`)
|
|
551
|
+
.option("--format <format>", "Output format (hint, json, markdown)", "hint")
|
|
552
|
+
.option("--quiet", "Suppress output if no results found")
|
|
553
|
+
.action(async (prompt, options) => {
|
|
554
|
+
try {
|
|
555
|
+
if (prompt.length < 10) {
|
|
556
|
+
if (!options.quiet) {
|
|
557
|
+
console.log("");
|
|
558
|
+
}
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
const validFormats = ["hint", "json", "markdown"];
|
|
562
|
+
if (!validFormats.includes(options.format)) {
|
|
563
|
+
if (options.format === "json") {
|
|
564
|
+
console.log(JSON.stringify({ success: false, error: `Invalid format. Use: ${validFormats.join(", ")}` }));
|
|
565
|
+
}
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
const limit = parseInt(options.limit, 10);
|
|
569
|
+
const minScore = parseFloat(options.minScore);
|
|
570
|
+
if (isNaN(limit) || limit < 1) {
|
|
571
|
+
if (options.format === "json") {
|
|
572
|
+
console.log(JSON.stringify({ success: false, error: "Invalid limit value" }));
|
|
573
|
+
}
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
576
|
+
if (isNaN(minScore) || minScore < 0 || minScore > 1) {
|
|
577
|
+
if (options.format === "json") {
|
|
578
|
+
console.log(JSON.stringify({ success: false, error: "min-score must be 0-1" }));
|
|
579
|
+
}
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
582
|
+
const brain = createBrain(options.agent, options.agentType);
|
|
583
|
+
const results = await brain.recall(prompt, limit, minScore);
|
|
584
|
+
if (results.length === 0) {
|
|
585
|
+
if (!options.quiet) {
|
|
586
|
+
console.log("");
|
|
587
|
+
}
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
if (options.format === "json") {
|
|
591
|
+
console.log(JSON.stringify({ success: true, results }));
|
|
592
|
+
return;
|
|
593
|
+
}
|
|
594
|
+
const truncate = (text, maxLen) => {
|
|
595
|
+
return text.length > maxLen ? `${text.slice(0, maxLen)}...` : text;
|
|
596
|
+
};
|
|
597
|
+
if (options.format === "markdown") {
|
|
598
|
+
console.log("\n## š§ Brain Recall - Relevante Erinnerungen\n");
|
|
599
|
+
for (const r of results) {
|
|
600
|
+
const tags = r.memory.tags.length > 0 ? ` (Tags: ${r.memory.tags.join(", ")})` : "";
|
|
601
|
+
console.log(`- **[${(r.score * 100).toFixed(0)}%]** ${truncate(r.memory.content, 150)}${tags}`);
|
|
602
|
+
}
|
|
603
|
+
console.log("");
|
|
604
|
+
return;
|
|
605
|
+
}
|
|
606
|
+
console.log("\nš§ BRAIN RECALL - Relevante Erinnerungen:");
|
|
607
|
+
console.log("ā".repeat(50));
|
|
608
|
+
for (const r of results) {
|
|
609
|
+
const tags = r.memory.tags.length > 0 ? ` [${r.memory.tags.join(", ")}]` : "";
|
|
610
|
+
console.log(` [${(r.score * 100).toFixed(0)}%] ${truncate(r.memory.content, 120)}${tags}`);
|
|
611
|
+
}
|
|
612
|
+
console.log("ā".repeat(50));
|
|
613
|
+
console.log("");
|
|
614
|
+
}
|
|
615
|
+
catch {
|
|
616
|
+
if (options.format === "json") {
|
|
617
|
+
console.log(JSON.stringify({ success: false, error: "recall failed" }));
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
});
|
|
621
|
+
brainCommand
|
|
622
|
+
.command("auto-remember <content>")
|
|
623
|
+
.description("Automatically store a learning/insight (for hook integration after task completion)")
|
|
624
|
+
.option("-a, --agent <id>", "Agent ID", DEFAULT_AGENT)
|
|
625
|
+
.option("--agent-type <type>", `Agent type for database selection (${AGENT_TYPES.join(", ")})`)
|
|
626
|
+
.option("--task-id <id>", "Associated task ID")
|
|
627
|
+
.option("-t, --tags <tags>", "Comma-separated tags", "auto-learning")
|
|
628
|
+
.option("--source <source>", "Source of learning (task, conversation, tool)", "task")
|
|
629
|
+
.option("--json", "Output as JSON")
|
|
630
|
+
.action(async (content, options) => {
|
|
631
|
+
try {
|
|
632
|
+
if (content.length < 20) {
|
|
633
|
+
if (options.json) {
|
|
634
|
+
console.log(JSON.stringify({ success: false, error: "Content too short" }));
|
|
635
|
+
}
|
|
636
|
+
return;
|
|
637
|
+
}
|
|
638
|
+
const brain = createBrain(options.agent, options.agentType);
|
|
639
|
+
const tags = options.tags.split(",").map((t) => t.trim());
|
|
640
|
+
if (options.source && !tags.includes(options.source)) {
|
|
641
|
+
tags.push(options.source);
|
|
642
|
+
}
|
|
643
|
+
if (options.taskId) {
|
|
644
|
+
tags.push(`task:${options.taskId}`);
|
|
645
|
+
}
|
|
646
|
+
const id = await brain.remember(content, tags, {
|
|
647
|
+
source: options.source,
|
|
648
|
+
taskId: options.taskId,
|
|
649
|
+
autoGenerated: true,
|
|
650
|
+
timestamp: new Date().toISOString(),
|
|
651
|
+
}, 'private', false);
|
|
652
|
+
if (options.json) {
|
|
653
|
+
console.log(JSON.stringify({ success: true, id, tags }));
|
|
654
|
+
}
|
|
655
|
+
else {
|
|
656
|
+
console.log(` ā Auto-Remember: ${id.slice(0, 8)}... [${tags.join(", ")}]`);
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
catch {
|
|
660
|
+
if (options.json) {
|
|
661
|
+
console.log(JSON.stringify({ success: false, error: "remember failed" }));
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
});
|
|
665
|
+
// ============================================================================
|
|
542
666
|
// Knowledge Base Commands
|
|
543
667
|
// ============================================================================
|
|
544
668
|
brainCommand
|
package/dist/lib/api-client.js
CHANGED
|
@@ -61,16 +61,21 @@ async function doFetch(url, method, authHeader, body) {
|
|
|
61
61
|
});
|
|
62
62
|
}
|
|
63
63
|
async function getAuthHeader(session, apiKey) {
|
|
64
|
+
// DEBUG: console.log('DEBUG session:', session?.token ? 'exists' : 'missing', session?.expiresAt);
|
|
64
65
|
if (session?.token && session.expiresAt) {
|
|
66
|
+
// DEBUG: console.log('DEBUG: Checking expiration...');
|
|
65
67
|
if (isSessionExpired(session.expiresAt)) {
|
|
68
|
+
// DEBUG: console.log('DEBUG: Session expired, refreshing...');
|
|
66
69
|
if (session.agent) {
|
|
67
70
|
const newSession = await refreshSession(session.agent);
|
|
68
71
|
if (newSession) {
|
|
72
|
+
// DEBUG: console.log('DEBUG: Refresh successful, using Bearer token');
|
|
69
73
|
return { "Authorization": `Bearer ${newSession.token}` };
|
|
70
74
|
}
|
|
71
75
|
}
|
|
72
76
|
clearSessionConfig();
|
|
73
77
|
if (apiKey) {
|
|
78
|
+
// DEBUG: console.log('DEBUG: Refresh failed, falling back to API key');
|
|
74
79
|
return { "x-api-key": apiKey };
|
|
75
80
|
}
|
|
76
81
|
throw new Error("Session expired and no API key available for refresh");
|
|
@@ -78,9 +83,11 @@ async function getAuthHeader(session, apiKey) {
|
|
|
78
83
|
if (isSessionExpiringSoon(session.expiresAt) && session.agent) {
|
|
79
84
|
refreshSession(session.agent).catch(() => { });
|
|
80
85
|
}
|
|
86
|
+
// DEBUG: console.log('DEBUG: Using existing Bearer token');
|
|
81
87
|
return { "Authorization": `Bearer ${session.token}` };
|
|
82
88
|
}
|
|
83
89
|
if (apiKey) {
|
|
90
|
+
// DEBUG: console.log('DEBUG: No session, using API key');
|
|
84
91
|
return { "x-api-key": apiKey };
|
|
85
92
|
}
|
|
86
93
|
throw new Error("No authentication configured. Run: husky auth login --agent <name> or husky config set api-key <key>");
|