@hivemindai/mcp-server 0.6.1 → 0.6.2
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/__tests__/config.test.js 2.map +1 -0
- package/dist/__tests__/credentials.test 2.js +126 -0
- package/dist/__tests__/credentials.test.d.ts 2.map +1 -0
- package/dist/__tests__/editor-config.test.d 2.ts +2 -0
- package/dist/__tests__/editor-config.test.js 2.map +1 -0
- package/dist/__tests__/format.test.d.ts 2.map +1 -0
- package/dist/__tests__/format.test.js 2.map +1 -0
- package/dist/__tests__/helpers/mock-server 2.js +107 -0
- package/dist/__tests__/helpers/mock-server.d 2.ts +79 -0
- package/dist/__tests__/helpers/mock-server.d.ts 2.map +1 -0
- package/dist/__tests__/helpers/mock-server.js 2.map +1 -0
- package/dist/__tests__/remember.test 2.js +152 -0
- package/dist/__tests__/tools-context.test 2.js +107 -0
- package/dist/__tests__/tools-context.test.js 2.map +1 -0
- package/dist/__tests__/tools-knowledge.test.d 2.ts +2 -0
- package/dist/__tests__/tools-knowledge.test.d.ts 2.map +1 -0
- package/dist/__tests__/tools-plans.test.d 2.ts +2 -0
- package/dist/__tests__/tools-plans.test.js 2.map +1 -0
- package/dist/__tests__/tools-schedules.test.js 2.map +1 -0
- package/dist/__tests__/tools-skills.test.d 2.ts +2 -0
- package/dist/__tests__/tools-skills.test.d.ts 2.map +1 -0
- package/dist/__tests__/tools-skills.test.js 2.map +1 -0
- package/dist/__tests__/tools-tasks.test 2.js +83 -0
- package/dist/__tests__/tools-tasks.test.d 2.ts +2 -0
- package/dist/__tests__/tools-triggers.test.d 2.ts +2 -0
- package/dist/__tests__/tools-workflows.test.d.ts 2.map +1 -0
- package/dist/__tests__/tools.test.d.ts 2.map +1 -0
- package/dist/cli/commands/context-inject 2.js +112 -0
- package/dist/cli/commands/context-inject.d 2.ts +2 -0
- package/dist/cli/commands/context-inject.d.ts 2.map +1 -0
- package/dist/cli/commands/context-inject.js 2.map +1 -0
- package/dist/cli/commands/doc 2.js +144 -0
- package/dist/cli/commands/doc.d.ts 2.map +1 -0
- package/dist/cli/commands/doc.js 2.map +1 -0
- package/dist/cli/commands/git-hook 2.js +79 -0
- package/dist/cli/commands/git-hook.d 3.ts +2 -0
- package/dist/cli/commands/git-hook.js 2.map +1 -0
- package/dist/cli/commands/guard 2.js +122 -0
- package/dist/cli/commands/guard.d.ts 2.map +1 -0
- package/dist/cli/commands/init 2.js +227 -0
- package/dist/cli/commands/init.d 2.ts +2 -0
- package/dist/cli/commands/init.d.ts 2.map +1 -0
- package/dist/cli/commands/init.js 2.map +1 -0
- package/dist/cli/commands/login 2.js +120 -0
- package/dist/cli/commands/login.d.ts 3.map +1 -0
- package/dist/cli/commands/logout 2.js +21 -0
- package/dist/cli/commands/logout.js 3.map +1 -0
- package/dist/cli/commands/release.d 3.ts +2 -0
- package/dist/cli/commands/release.d.ts 2.map +1 -0
- package/dist/cli/commands/release.js 2.map +1 -0
- package/dist/cli/commands/skill 2.js +185 -0
- package/dist/cli/commands/skill-inject 2.js +194 -0
- package/dist/cli/commands/skill-inject.d 2.ts +2 -0
- package/dist/cli/commands/skill-inject.d.ts 2.map +1 -0
- package/dist/cli/commands/skill-inject.js 2.map +1 -0
- package/dist/cli/commands/skill.d 2.ts +2 -0
- package/dist/cli/commands/status 2.js +45 -0
- package/dist/cli/commands/status.d.ts 2.map +1 -0
- package/dist/cli/commands/status.d.ts 3.map +1 -0
- package/dist/cli/commands/status.js 2.map +1 -0
- package/dist/cli/commands/switch 2.js +88 -0
- package/dist/cli/commands/switch 3.js +88 -0
- package/dist/cli/commands/switch.js 2.map +1 -0
- package/dist/cli/commands/whoami.d 2.ts +2 -0
- package/dist/cli/commands/whoami.d 3.ts +2 -0
- package/dist/cli/commands/whoami.d.ts 2.map +1 -0
- package/dist/cli/commands/whoami.js 2.map +1 -0
- package/dist/cli/commands/whoami.js 3.map +1 -0
- package/dist/cli/credentials.js 2.map +1 -0
- package/dist/cli/editor-config 2.js +109 -0
- package/dist/cli/editor-config.d 2.ts +9 -0
- package/dist/cli/editor-config.d.ts 2.map +1 -0
- package/dist/cli/editor-config.js 2.map +1 -0
- package/dist/cli/index 2.d 2.ts +2 -0
- package/dist/cli/index 2.d.ts 2.map +1 -0
- package/dist/cli/index 2.js 2.map +1 -0
- package/dist/cli/index 3.js +63 -0
- package/dist/cli/index 4.js +68 -0
- package/dist/cli/index.js 2.map +1 -0
- package/dist/tools/approvals.d.ts 2.map +1 -0
- package/dist/tools/blockers 2.js +24 -0
- package/dist/tools/blockers.d 2.ts +21 -0
- package/dist/tools/blockers.d.ts 2.map +1 -0
- package/dist/tools/handoffs.d.ts 2.map +1 -0
- package/dist/tools/knowledge.d.ts 2.map +1 -0
- package/dist/tools/knowledge.js 3.map +1 -0
- package/dist/tools/lock.d 2.ts +24 -0
- package/dist/tools/lock.d.ts 2.map +1 -0
- package/dist/tools/lock.js 2.map +1 -0
- package/dist/tools/plans.d 2.ts +5 -0
- package/dist/tools/publish.d 2.ts +24 -0
- package/dist/tools/publish.d.ts 2.map +1 -0
- package/dist/tools/query 2.js +41 -0
- package/dist/tools/query.d 2.ts +27 -0
- package/dist/tools/query.js 2.map +1 -0
- package/dist/tools/remember.js 2.map +1 -0
- package/dist/tools/skills 2.js +273 -0
- package/dist/tools/skills.js 2.map +1 -0
- package/dist/tools/status.d.ts 2.map +1 -0
- package/dist/tools/status.js 2.map +1 -0
- package/dist/tools/subscribe.js 2.map +1 -0
- package/dist/tools/tasks 2.js +51 -0
- package/dist/tools/teams.d 2.ts +4 -0
- package/dist/tools/teams.js 2.map +1 -0
- package/dist/tools/triggers 2.js +212 -0
- package/dist/tools/triggers.d 2.ts +5 -0
- package/dist/tools/triggers.d.ts 2.map +1 -0
- package/dist/tools/triggers.d.ts 3.map +1 -0
- package/dist/tools/workflows.d.ts 2.map +1 -0
- package/package.json +3 -3
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { HivemindClient } from "@hivemindai/sdk-ts";
|
|
3
|
+
import { readCredentials } from "../credentials.js";
|
|
4
|
+
export async function skill(args) {
|
|
5
|
+
const creds = readCredentials();
|
|
6
|
+
if (!creds) {
|
|
7
|
+
console.log("Not logged in. Run `hivemind login` to authenticate.");
|
|
8
|
+
process.exit(1);
|
|
9
|
+
}
|
|
10
|
+
const client = new HivemindClient({
|
|
11
|
+
apiKey: creds.api_key,
|
|
12
|
+
baseUrl: creds.api_url,
|
|
13
|
+
});
|
|
14
|
+
const subcommand = args[0];
|
|
15
|
+
if (!subcommand || subcommand === "--help") {
|
|
16
|
+
console.log(`
|
|
17
|
+
Usage: hivemind skill <subcommand>
|
|
18
|
+
|
|
19
|
+
Subcommands:
|
|
20
|
+
add --name <name> --description <desc> --instructions <text> | --file <path>
|
|
21
|
+
[--tags t1,t2] [--trigger-files "*.tsx,*.ts"] [--trigger-tools "Edit,Write"]
|
|
22
|
+
[--trigger-keywords "test,deploy"]
|
|
23
|
+
list List all skills
|
|
24
|
+
search <query> Semantic search
|
|
25
|
+
get <id> Get skill details
|
|
26
|
+
update <id> Update skill fields
|
|
27
|
+
delete <id> Delete skill
|
|
28
|
+
`.trim());
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
if (subcommand === "add") {
|
|
33
|
+
const name = getFlag(args, "--name");
|
|
34
|
+
if (!name) {
|
|
35
|
+
console.error("Usage: hivemind skill add --name <name> --description <desc> --instructions <text>");
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
const description = getFlag(args, "--description");
|
|
39
|
+
if (!description) {
|
|
40
|
+
console.error("--description is required");
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
let instructions = getFlag(args, "--instructions");
|
|
44
|
+
const filePath = getFlag(args, "--file");
|
|
45
|
+
if (filePath) {
|
|
46
|
+
instructions = readFileSync(filePath, "utf-8");
|
|
47
|
+
}
|
|
48
|
+
if (!instructions) {
|
|
49
|
+
console.error("Provide instructions via --instructions or --file");
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
const tags = getFlag(args, "--tags")?.split(",").map((t) => t.trim());
|
|
53
|
+
const triggers = {};
|
|
54
|
+
const triggerFiles = getFlag(args, "--trigger-files");
|
|
55
|
+
if (triggerFiles)
|
|
56
|
+
triggers.file_patterns = triggerFiles.split(",").map((t) => t.trim());
|
|
57
|
+
const triggerTools = getFlag(args, "--trigger-tools");
|
|
58
|
+
if (triggerTools)
|
|
59
|
+
triggers.tools = triggerTools.split(",").map((t) => t.trim());
|
|
60
|
+
const triggerKeywords = getFlag(args, "--trigger-keywords");
|
|
61
|
+
if (triggerKeywords)
|
|
62
|
+
triggers.keywords = triggerKeywords.split(",").map((t) => t.trim());
|
|
63
|
+
const result = await client.addSkill({
|
|
64
|
+
name,
|
|
65
|
+
description,
|
|
66
|
+
instructions,
|
|
67
|
+
tags,
|
|
68
|
+
triggers: Object.keys(triggers).length > 0 ? triggers : undefined,
|
|
69
|
+
});
|
|
70
|
+
console.log(`Skill created: ${result.id}`);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (subcommand === "list") {
|
|
74
|
+
const result = await client.listSkills();
|
|
75
|
+
if (result.skills.length === 0) {
|
|
76
|
+
console.log("No skills found.");
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
console.log(`Skills (${result.total})\n`);
|
|
80
|
+
for (const s of result.skills) {
|
|
81
|
+
const tags = s.tags?.length ? ` [${s.tags.join(", ")}]` : "";
|
|
82
|
+
console.log(` ${s.id} ${s.name}${tags} — ${s.description}`);
|
|
83
|
+
}
|
|
84
|
+
if (result.has_more) {
|
|
85
|
+
console.log("\n (more skills available)");
|
|
86
|
+
}
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (subcommand === "search") {
|
|
90
|
+
const query = args[1];
|
|
91
|
+
if (!query) {
|
|
92
|
+
console.error("Usage: hivemind skill search <query>");
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
const result = await client.searchSkills(query);
|
|
96
|
+
if (result.skills.length === 0) {
|
|
97
|
+
console.log("No matching skills found.");
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
console.log(`Search Results (${result.total})\n`);
|
|
101
|
+
for (const s of result.skills) {
|
|
102
|
+
const score = s._score !== undefined ? ` (${(s._score * 100).toFixed(0)}%)` : "";
|
|
103
|
+
console.log(` ${s.id} ${s.name}${score} — ${s.description}`);
|
|
104
|
+
}
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
if (subcommand === "get") {
|
|
108
|
+
const skillId = args[1];
|
|
109
|
+
if (!skillId) {
|
|
110
|
+
console.error("Usage: hivemind skill get <skill_id>");
|
|
111
|
+
process.exit(1);
|
|
112
|
+
}
|
|
113
|
+
const result = await client.getSkill(skillId);
|
|
114
|
+
const s = result.skill;
|
|
115
|
+
const tags = s.tags?.length ? `\nTags: ${s.tags.join(", ")}` : "";
|
|
116
|
+
const triggers = s.triggers && Object.keys(s.triggers).length > 0
|
|
117
|
+
? `\nTriggers: ${JSON.stringify(s.triggers)}`
|
|
118
|
+
: "";
|
|
119
|
+
console.log(`${s.name}\nID: ${s.id}\nDescription: ${s.description}${tags}${triggers}\nUpdated: ${s.updated_at}\n\n${s.instructions}`);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
if (subcommand === "update") {
|
|
123
|
+
const skillId = args[1];
|
|
124
|
+
if (!skillId) {
|
|
125
|
+
console.error("Usage: hivemind skill update <skill_id> [--name ...] [--description ...] [--instructions ...] [--file ...]");
|
|
126
|
+
process.exit(1);
|
|
127
|
+
}
|
|
128
|
+
const updateParams = {};
|
|
129
|
+
const name = getFlag(args, "--name");
|
|
130
|
+
if (name)
|
|
131
|
+
updateParams.name = name;
|
|
132
|
+
const description = getFlag(args, "--description");
|
|
133
|
+
if (description)
|
|
134
|
+
updateParams.description = description;
|
|
135
|
+
let instructions = getFlag(args, "--instructions");
|
|
136
|
+
const filePath = getFlag(args, "--file");
|
|
137
|
+
if (filePath)
|
|
138
|
+
instructions = readFileSync(filePath, "utf-8");
|
|
139
|
+
if (instructions)
|
|
140
|
+
updateParams.instructions = instructions;
|
|
141
|
+
const tagsStr = getFlag(args, "--tags");
|
|
142
|
+
if (tagsStr)
|
|
143
|
+
updateParams.tags = tagsStr.split(",").map((t) => t.trim());
|
|
144
|
+
const triggers = {};
|
|
145
|
+
const triggerFiles = getFlag(args, "--trigger-files");
|
|
146
|
+
if (triggerFiles)
|
|
147
|
+
triggers.file_patterns = triggerFiles.split(",").map((t) => t.trim());
|
|
148
|
+
const triggerTools = getFlag(args, "--trigger-tools");
|
|
149
|
+
if (triggerTools)
|
|
150
|
+
triggers.tools = triggerTools.split(",").map((t) => t.trim());
|
|
151
|
+
const triggerKeywords = getFlag(args, "--trigger-keywords");
|
|
152
|
+
if (triggerKeywords)
|
|
153
|
+
triggers.keywords = triggerKeywords.split(",").map((t) => t.trim());
|
|
154
|
+
if (Object.keys(triggers).length > 0)
|
|
155
|
+
updateParams.triggers = triggers;
|
|
156
|
+
const result = await client.updateSkill(skillId, updateParams);
|
|
157
|
+
console.log(result.updated ? `Skill ${skillId} updated.` : `Skill ${skillId} not found.`);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
if (subcommand === "delete") {
|
|
161
|
+
const skillId = args[1];
|
|
162
|
+
if (!skillId) {
|
|
163
|
+
console.error("Usage: hivemind skill delete <skill_id>");
|
|
164
|
+
process.exit(1);
|
|
165
|
+
}
|
|
166
|
+
const result = await client.deleteSkill(skillId);
|
|
167
|
+
console.log(result.deleted ? `Skill ${skillId} deleted.` : `Skill ${skillId} not found.`);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
console.error(`Unknown subcommand: ${subcommand}`);
|
|
171
|
+
console.error('Run "hivemind skill --help" for usage.');
|
|
172
|
+
process.exit(1);
|
|
173
|
+
}
|
|
174
|
+
catch (err) {
|
|
175
|
+
console.error(`Failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
176
|
+
process.exit(1);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
function getFlag(args, flag) {
|
|
180
|
+
const idx = args.indexOf(flag);
|
|
181
|
+
if (idx === -1 || idx + 1 >= args.length)
|
|
182
|
+
return undefined;
|
|
183
|
+
return args[idx + 1];
|
|
184
|
+
}
|
|
185
|
+
//# sourceMappingURL=skill.js.map
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { readFileSync, existsSync, writeFileSync, mkdirSync, readdirSync, unlinkSync, statSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
function loadCredentials() {
|
|
4
|
+
const credPath = join(process.env.HOME ?? process.env.USERPROFILE ?? ".", ".hivemind", "credentials.json");
|
|
5
|
+
if (!existsSync(credPath))
|
|
6
|
+
return null;
|
|
7
|
+
try {
|
|
8
|
+
const creds = JSON.parse(readFileSync(credPath, "utf-8"));
|
|
9
|
+
return { api_key: creds.api_key, api_url: creds.api_url };
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function getSessionsDir() {
|
|
16
|
+
const home = process.env.HOME ?? process.env.USERPROFILE ?? ".";
|
|
17
|
+
return join(home, ".hivemind", "sessions");
|
|
18
|
+
}
|
|
19
|
+
function isFirstCall(sessionId) {
|
|
20
|
+
const sessionsDir = getSessionsDir();
|
|
21
|
+
const flagFile = join(sessionsDir, `${sessionId}.first`);
|
|
22
|
+
if (existsSync(flagFile))
|
|
23
|
+
return false;
|
|
24
|
+
try {
|
|
25
|
+
mkdirSync(sessionsDir, { recursive: true });
|
|
26
|
+
writeFileSync(flagFile, new Date().toISOString());
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
// Cleanup old flag files (>24h) — non-blocking best-effort
|
|
32
|
+
try {
|
|
33
|
+
const cutoff = Date.now() - 24 * 60 * 60 * 1000;
|
|
34
|
+
for (const f of readdirSync(sessionsDir)) {
|
|
35
|
+
if (!f.endsWith(".first"))
|
|
36
|
+
continue;
|
|
37
|
+
const fullPath = join(sessionsDir, f);
|
|
38
|
+
try {
|
|
39
|
+
const stat = statSync(fullPath);
|
|
40
|
+
if (stat.mtimeMs < cutoff)
|
|
41
|
+
unlinkSync(fullPath);
|
|
42
|
+
}
|
|
43
|
+
catch { /* ignore */ }
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch { /* ignore */ }
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
async function injectSessionContext(creds, headers) {
|
|
50
|
+
const output = [];
|
|
51
|
+
// Fetch onboarding context, raw context, patterns, and stale docs in parallel
|
|
52
|
+
const [onboardingRes, contextRes, patternsRes, staleRes] = await Promise.all([
|
|
53
|
+
fetch(`${creds.api_url}/v1/intelligence/onboarding`, { headers }).catch(() => null),
|
|
54
|
+
fetch(`${creds.api_url}/v1/intelligence/context`, { headers }).catch(() => null),
|
|
55
|
+
fetch(`${creds.api_url}/v1/intelligence/patterns?limit=5`, { headers }).catch(() => null),
|
|
56
|
+
fetch(`${creds.api_url}/v1/knowledge/stale`, { headers }).catch(() => null),
|
|
57
|
+
]);
|
|
58
|
+
// If onboarding context exists, use it as the primary context
|
|
59
|
+
let usedOnboarding = false;
|
|
60
|
+
if (onboardingRes?.ok) {
|
|
61
|
+
const data = await onboardingRes.json();
|
|
62
|
+
if (data.content) {
|
|
63
|
+
output.push(data.content);
|
|
64
|
+
usedOnboarding = true;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// Fall back to raw context if no onboarding brief
|
|
68
|
+
if (!usedOnboarding && contextRes?.ok) {
|
|
69
|
+
const ctx = await contextRes.json();
|
|
70
|
+
if (ctx.active_tasks?.length > 0) {
|
|
71
|
+
output.push(`Active Tasks (${ctx.active_tasks.length}):`);
|
|
72
|
+
for (const t of ctx.active_tasks.slice(0, 5)) {
|
|
73
|
+
output.push(` - [${t.channel}] ${t.description ?? t.id} (by ${t.source?.agent ?? "unknown"})`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (ctx.blockers?.length > 0) {
|
|
77
|
+
output.push(`Blockers (${ctx.blockers.length}):`);
|
|
78
|
+
for (const b of ctx.blockers) {
|
|
79
|
+
output.push(` - [${b.channel}] ${b.description ?? b.id}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (ctx.recent_decisions?.length > 0) {
|
|
83
|
+
output.push(`Recent Decisions:`);
|
|
84
|
+
for (const d of ctx.recent_decisions.slice(0, 3)) {
|
|
85
|
+
output.push(` - [${d.channel}] ${d.description ?? JSON.stringify(d.data)}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (ctx.active_locks?.length > 0) {
|
|
89
|
+
output.push(`Active Locks:`);
|
|
90
|
+
for (const l of ctx.active_locks) {
|
|
91
|
+
output.push(` - ${l.resource} (held by ${l.agent})`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (!usedOnboarding && patternsRes?.ok) {
|
|
96
|
+
const data = await patternsRes.json();
|
|
97
|
+
if (data.patterns?.length > 0) {
|
|
98
|
+
output.push(`Learned Patterns:`);
|
|
99
|
+
for (const p of data.patterns) {
|
|
100
|
+
output.push(` - [${p.pattern_type}] ${p.description} (seen ${p.frequency}x)`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// Add stale knowledge warning
|
|
105
|
+
if (staleRes?.ok) {
|
|
106
|
+
const data = await staleRes.json();
|
|
107
|
+
if (data.docs?.length > 0) {
|
|
108
|
+
output.push(`\nWarning: ${data.docs.length} knowledge doc${data.docs.length > 1 ? "s" : ""} may be outdated — run \`hivemind_knowledge(action: 'list-stale')\` to review.`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if (output.length > 0) {
|
|
112
|
+
process.stderr.write(`=== Hivemind Session Context ===\n${output.join("\n")}\n===\n\n`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
export async function skillInject() {
|
|
116
|
+
// 1. Read hook input from stdin
|
|
117
|
+
let input;
|
|
118
|
+
try {
|
|
119
|
+
const raw = readFileSync(0, "utf-8");
|
|
120
|
+
input = JSON.parse(raw);
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
process.exit(0);
|
|
124
|
+
}
|
|
125
|
+
// 2. Load credentials (cloud only)
|
|
126
|
+
const creds = loadCredentials();
|
|
127
|
+
if (!creds)
|
|
128
|
+
process.exit(0);
|
|
129
|
+
const headers = { Authorization: `Bearer ${creds.api_key}` };
|
|
130
|
+
// 3. First-call session context injection
|
|
131
|
+
const sessionId = input.session_id ?? `pid-${process.ppid}`;
|
|
132
|
+
if (isFirstCall(sessionId)) {
|
|
133
|
+
try {
|
|
134
|
+
await injectSessionContext(creds, headers);
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
// Don't block on errors
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// 4. Extract context
|
|
141
|
+
const filePath = input.tool_input?.file_path;
|
|
142
|
+
const command = input.tool_input?.command;
|
|
143
|
+
const toolName = input.tool_name;
|
|
144
|
+
// 5. Make relative path
|
|
145
|
+
const cwd = input.cwd ?? process.cwd();
|
|
146
|
+
let resource = filePath ?? "";
|
|
147
|
+
if (resource.startsWith(cwd)) {
|
|
148
|
+
resource = resource.slice(cwd.length).replace(/^\//, "");
|
|
149
|
+
}
|
|
150
|
+
// 6. Call match endpoint + decision replay in parallel
|
|
151
|
+
const params = new URLSearchParams();
|
|
152
|
+
if (toolName)
|
|
153
|
+
params.set("tool", toolName);
|
|
154
|
+
if (resource)
|
|
155
|
+
params.set("file", resource);
|
|
156
|
+
if (command)
|
|
157
|
+
params.set("command", command);
|
|
158
|
+
const fetches = [];
|
|
159
|
+
// Skill match
|
|
160
|
+
fetches.push((async () => {
|
|
161
|
+
try {
|
|
162
|
+
const res = await fetch(`${creds.api_url}/v1/skills/match?${params}`, { headers });
|
|
163
|
+
if (!res.ok)
|
|
164
|
+
return;
|
|
165
|
+
const data = await res.json();
|
|
166
|
+
if (data.skills?.length > 0) {
|
|
167
|
+
const output = data.skills
|
|
168
|
+
.map((s) => `--- Skill: ${s.name} ---\n${s.instructions}\n---`)
|
|
169
|
+
.join("\n\n");
|
|
170
|
+
process.stderr.write(output);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
catch { /* ignore */ }
|
|
174
|
+
})());
|
|
175
|
+
// Decision replay by file context (Part 5)
|
|
176
|
+
if (resource) {
|
|
177
|
+
fetches.push((async () => {
|
|
178
|
+
try {
|
|
179
|
+
const res = await fetch(`${creds.api_url}/v1/intelligence/context?file=${encodeURIComponent(resource)}`, { headers });
|
|
180
|
+
if (!res.ok)
|
|
181
|
+
return;
|
|
182
|
+
const ctx = await res.json();
|
|
183
|
+
if (ctx.recent_decisions?.length > 0) {
|
|
184
|
+
const lines = ctx.recent_decisions.map((d) => ` - ${d.description ?? JSON.stringify(d.data)} (${d.created_at})`);
|
|
185
|
+
process.stderr.write(`\n--- Decisions affecting ${resource} ---\n${lines.join("\n")}\n---\n`);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
catch { /* ignore */ }
|
|
189
|
+
})());
|
|
190
|
+
}
|
|
191
|
+
await Promise.all(fetches);
|
|
192
|
+
process.exit(0); // Always allow — skills never block
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=skill-inject.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-inject.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/skill-inject.ts"],"names":[],"mappings":"AA+IA,wBAAsB,WAAW,kBA+FhC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-inject.js","sourceRoot":"","sources":["../../../src/cli/commands/skill-inject.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { HivemindClient } from "@hivemindai/sdk-ts";
|
|
2
|
+
import { readCredentials } from "../credentials.js";
|
|
3
|
+
export async function status() {
|
|
4
|
+
const creds = readCredentials();
|
|
5
|
+
if (!creds) {
|
|
6
|
+
console.log("Not logged in. Run `hivemind login` to authenticate.");
|
|
7
|
+
process.exit(1);
|
|
8
|
+
}
|
|
9
|
+
const client = new HivemindClient({
|
|
10
|
+
apiKey: creds.api_key,
|
|
11
|
+
baseUrl: creds.api_url,
|
|
12
|
+
});
|
|
13
|
+
try {
|
|
14
|
+
const res = await client.status();
|
|
15
|
+
console.log(`Org: ${creds.org_name}\n`);
|
|
16
|
+
console.log(`Events (24h): ${res.event_count_24h}`);
|
|
17
|
+
console.log(`Last event: ${res.last_event_at ?? "none"}`);
|
|
18
|
+
if (res.active_tasks.length > 0) {
|
|
19
|
+
console.log(`\nActive tasks (${res.active_tasks.length}):`);
|
|
20
|
+
for (const task of res.active_tasks) {
|
|
21
|
+
const summary = task.data.summary ?? task.channel;
|
|
22
|
+
console.log(` - ${summary}`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (res.blockers.length > 0) {
|
|
26
|
+
console.log(`\nBlockers (${res.blockers.length}):`);
|
|
27
|
+
for (const blocker of res.blockers) {
|
|
28
|
+
const summary = blocker.data.summary ?? blocker.channel;
|
|
29
|
+
console.log(` - ${summary}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (res.recent_completions.length > 0) {
|
|
33
|
+
console.log(`\nRecent completions (${res.recent_completions.length}):`);
|
|
34
|
+
for (const c of res.recent_completions) {
|
|
35
|
+
const summary = c.data.summary ?? c.channel;
|
|
36
|
+
console.log(` - ${summary}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
console.error(`Failed to fetch status: ${err instanceof Error ? err.message : String(err)}`);
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/status.ts"],"names":[],"mappings":"AAGA,wBAAsB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CA+C5C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/status.ts"],"names":[],"mappings":"AAGA,wBAAsB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CA+C5C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../../src/cli/commands/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,MAAM,CAAC,KAAK,UAAU,MAAM;IAC1B,MAAM,KAAK,GAAG,eAAe,EAAE,CAAC;IAEhC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,GAAG,CAAC,sDAAsD,CAAC,CAAC;QACpE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,cAAc,CAAC;QAChC,MAAM,EAAE,KAAK,CAAC,OAAO;QACrB,OAAO,EAAE,KAAK,CAAC,OAAO;KACvB,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC;QAElC,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,CAAC,QAAQ,IAAI,CAAC,CAAC;QACxC,OAAO,CAAC,GAAG,CAAC,kBAAkB,GAAG,CAAC,eAAe,EAAE,CAAC,CAAC;QACrD,OAAO,CAAC,GAAG,CAAC,kBAAkB,GAAG,CAAC,aAAa,IAAI,MAAM,EAAE,CAAC,CAAC;QAE7D,IAAI,GAAG,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAChC,OAAO,CAAC,GAAG,CAAC,mBAAmB,GAAG,CAAC,YAAY,CAAC,MAAM,IAAI,CAAC,CAAC;YAC5D,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,YAAY,EAAE,CAAC;gBACpC,MAAM,OAAO,GAAI,IAAI,CAAC,IAAgC,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC;gBAC/E,OAAO,CAAC,GAAG,CAAC,OAAO,OAAO,EAAE,CAAC,CAAC;YAChC,CAAC;QACH,CAAC;QAED,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,OAAO,CAAC,GAAG,CAAC,eAAe,GAAG,CAAC,QAAQ,CAAC,MAAM,IAAI,CAAC,CAAC;YACpD,KAAK,MAAM,OAAO,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;gBACnC,MAAM,OAAO,GAAI,OAAO,CAAC,IAAgC,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;gBACrF,OAAO,CAAC,GAAG,CAAC,OAAO,OAAO,EAAE,CAAC,CAAC;YAChC,CAAC;QACH,CAAC;QAED,IAAI,GAAG,CAAC,kBAAkB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtC,OAAO,CAAC,GAAG,CAAC,yBAAyB,GAAG,CAAC,kBAAkB,CAAC,MAAM,IAAI,CAAC,CAAC;YACxE,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,kBAAkB,EAAE,CAAC;gBACvC,MAAM,OAAO,GAAI,CAAC,CAAC,IAAgC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,CAAC;gBACzE,OAAO,CAAC,GAAG,CAAC,OAAO,OAAO,EAAE,CAAC,CAAC;YAChC,CAAC;QACH,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,2BAA2B,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC7F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { createServer } from "node:http";
|
|
2
|
+
import { execSync } from "node:child_process";
|
|
3
|
+
import { URL } from "node:url";
|
|
4
|
+
import { writeCredentials, readCredentials } from "../credentials.js";
|
|
5
|
+
const SWITCH_TIMEOUT_MS = 120_000;
|
|
6
|
+
function openBrowser(url) {
|
|
7
|
+
const platform = process.platform;
|
|
8
|
+
try {
|
|
9
|
+
if (platform === "darwin") {
|
|
10
|
+
execSync(`open "${url}"`);
|
|
11
|
+
}
|
|
12
|
+
else if (platform === "win32") {
|
|
13
|
+
execSync(`start "" "${url}"`);
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
execSync(`xdg-open "${url}"`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
console.log(`\nOpen this URL in your browser:\n ${url}\n`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export async function switchOrg() {
|
|
24
|
+
const existing = readCredentials();
|
|
25
|
+
if (!existing) {
|
|
26
|
+
console.log("Not logged in. Run `hivemind login` first.");
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
console.log(`Currently logged in as ${existing.email} (org: ${existing.org_name})`);
|
|
30
|
+
console.log("Opening browser to switch organization...\n");
|
|
31
|
+
const dashboardUrl = process.env.HIVEMIND_DASHBOARD_URL ?? "https://hivemindai.dev";
|
|
32
|
+
const creds = await new Promise((resolve, reject) => {
|
|
33
|
+
const server = createServer((req, res) => {
|
|
34
|
+
if (!req.url?.startsWith("/callback")) {
|
|
35
|
+
res.writeHead(404);
|
|
36
|
+
res.end("Not found");
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const url = new URL(req.url, `http://localhost`);
|
|
40
|
+
const apiKey = url.searchParams.get("key");
|
|
41
|
+
const orgId = url.searchParams.get("org_id");
|
|
42
|
+
const orgName = url.searchParams.get("org_name");
|
|
43
|
+
const orgSlug = url.searchParams.get("org_slug");
|
|
44
|
+
const email = url.searchParams.get("email");
|
|
45
|
+
const apiUrl = url.searchParams.get("api_url");
|
|
46
|
+
if (!apiKey || !orgId || !email) {
|
|
47
|
+
res.writeHead(400, { "Content-Type": "text/html" });
|
|
48
|
+
res.end("<html><body><h2>Missing required parameters.</h2><p>Please try again.</p></body></html>");
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const credentials = {
|
|
52
|
+
api_key: apiKey,
|
|
53
|
+
api_url: apiUrl ?? existing.api_url,
|
|
54
|
+
org_id: orgId,
|
|
55
|
+
org_name: orgName ?? "",
|
|
56
|
+
org_slug: orgSlug ?? "",
|
|
57
|
+
email,
|
|
58
|
+
};
|
|
59
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
60
|
+
res.end(`<html><body>
|
|
61
|
+
<h2>Organization switched!</h2>
|
|
62
|
+
<p>You can close this tab and return to your terminal.</p>
|
|
63
|
+
</body></html>`);
|
|
64
|
+
server.close();
|
|
65
|
+
resolve(credentials);
|
|
66
|
+
});
|
|
67
|
+
server.listen(0, "127.0.0.1", () => {
|
|
68
|
+
const addr = server.address();
|
|
69
|
+
if (!addr || typeof addr === "string") {
|
|
70
|
+
reject(new Error("Failed to start local server"));
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const port = addr.port;
|
|
74
|
+
const callbackUrl = encodeURIComponent(`http://localhost:${port}/callback`);
|
|
75
|
+
const authUrl = `${dashboardUrl}/cli-switch?callback_url=${callbackUrl}`;
|
|
76
|
+
openBrowser(authUrl);
|
|
77
|
+
});
|
|
78
|
+
setTimeout(() => {
|
|
79
|
+
server.close();
|
|
80
|
+
reject(new Error("Switch timed out. Please try again."));
|
|
81
|
+
}, SWITCH_TIMEOUT_MS);
|
|
82
|
+
});
|
|
83
|
+
writeCredentials(creds);
|
|
84
|
+
console.log(`Switched to org: ${creds.org_name} (${creds.org_id})`);
|
|
85
|
+
console.log(`API key updated in ~/.hivemind/credentials.json`);
|
|
86
|
+
console.log(`\nRestart Claude Code to use the new organization.`);
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=switch.js.map
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { createServer } from "node:http";
|
|
2
|
+
import { execSync } from "node:child_process";
|
|
3
|
+
import { URL } from "node:url";
|
|
4
|
+
import { writeCredentials, readCredentials } from "../credentials.js";
|
|
5
|
+
const SWITCH_TIMEOUT_MS = 120_000;
|
|
6
|
+
function openBrowser(url) {
|
|
7
|
+
const platform = process.platform;
|
|
8
|
+
try {
|
|
9
|
+
if (platform === "darwin") {
|
|
10
|
+
execSync(`open "${url}"`);
|
|
11
|
+
}
|
|
12
|
+
else if (platform === "win32") {
|
|
13
|
+
execSync(`start "" "${url}"`);
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
execSync(`xdg-open "${url}"`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
console.log(`\nOpen this URL in your browser:\n ${url}\n`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export async function switchOrg() {
|
|
24
|
+
const existing = readCredentials();
|
|
25
|
+
if (!existing) {
|
|
26
|
+
console.log("Not logged in. Run `hivemind login` first.");
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
console.log(`Currently logged in as ${existing.email} (org: ${existing.org_name})`);
|
|
30
|
+
console.log("Opening browser to switch organization...\n");
|
|
31
|
+
const dashboardUrl = process.env.HIVEMIND_DASHBOARD_URL ?? "https://hivemindai.dev";
|
|
32
|
+
const creds = await new Promise((resolve, reject) => {
|
|
33
|
+
const server = createServer((req, res) => {
|
|
34
|
+
if (!req.url?.startsWith("/callback")) {
|
|
35
|
+
res.writeHead(404);
|
|
36
|
+
res.end("Not found");
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const url = new URL(req.url, `http://localhost`);
|
|
40
|
+
const apiKey = url.searchParams.get("key");
|
|
41
|
+
const orgId = url.searchParams.get("org_id");
|
|
42
|
+
const orgName = url.searchParams.get("org_name");
|
|
43
|
+
const orgSlug = url.searchParams.get("org_slug");
|
|
44
|
+
const email = url.searchParams.get("email");
|
|
45
|
+
const apiUrl = url.searchParams.get("api_url");
|
|
46
|
+
if (!apiKey || !orgId || !email) {
|
|
47
|
+
res.writeHead(400, { "Content-Type": "text/html" });
|
|
48
|
+
res.end("<html><body><h2>Missing required parameters.</h2><p>Please try again.</p></body></html>");
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const credentials = {
|
|
52
|
+
api_key: apiKey,
|
|
53
|
+
api_url: apiUrl ?? existing.api_url,
|
|
54
|
+
org_id: orgId,
|
|
55
|
+
org_name: orgName ?? "",
|
|
56
|
+
org_slug: orgSlug ?? "",
|
|
57
|
+
email,
|
|
58
|
+
};
|
|
59
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
60
|
+
res.end(`<html><body>
|
|
61
|
+
<h2>Organization switched!</h2>
|
|
62
|
+
<p>You can close this tab and return to your terminal.</p>
|
|
63
|
+
</body></html>`);
|
|
64
|
+
server.close();
|
|
65
|
+
resolve(credentials);
|
|
66
|
+
});
|
|
67
|
+
server.listen(0, "127.0.0.1", () => {
|
|
68
|
+
const addr = server.address();
|
|
69
|
+
if (!addr || typeof addr === "string") {
|
|
70
|
+
reject(new Error("Failed to start local server"));
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const port = addr.port;
|
|
74
|
+
const callbackUrl = encodeURIComponent(`http://localhost:${port}/callback`);
|
|
75
|
+
const authUrl = `${dashboardUrl}/cli-switch?callback_url=${callbackUrl}`;
|
|
76
|
+
openBrowser(authUrl);
|
|
77
|
+
});
|
|
78
|
+
setTimeout(() => {
|
|
79
|
+
server.close();
|
|
80
|
+
reject(new Error("Switch timed out. Please try again."));
|
|
81
|
+
}, SWITCH_TIMEOUT_MS);
|
|
82
|
+
});
|
|
83
|
+
writeCredentials(creds);
|
|
84
|
+
console.log(`Switched to org: ${creds.org_name} (${creds.org_id})`);
|
|
85
|
+
console.log(`API key updated in ~/.hivemind/credentials.json`);
|
|
86
|
+
console.log(`\nRestart Claude Code to use the new organization.`);
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=switch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"switch.js","sourceRoot":"","sources":["../../../src/cli/commands/switch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"whoami.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/whoami.ts"],"names":[],"mappings":"AAEA,wBAAsB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAiC5C"}
|