haansi 0.1.14 → 0.1.16
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/haansi.js +231 -85
- package/package.json +1 -1
package/dist/haansi.js
CHANGED
|
@@ -39,7 +39,7 @@ var require_package = __commonJS({
|
|
|
39
39
|
"package.json"(exports2, module2) {
|
|
40
40
|
module2.exports = {
|
|
41
41
|
name: "haansi",
|
|
42
|
-
version: "0.1.
|
|
42
|
+
version: "0.1.16",
|
|
43
43
|
description: "Haansi CLI - Session collector and MCP server for Claude Code",
|
|
44
44
|
bin: {
|
|
45
45
|
haansi: "./dist/haansi.js"
|
|
@@ -64,6 +64,129 @@ var require_package = __commonJS({
|
|
|
64
64
|
}
|
|
65
65
|
});
|
|
66
66
|
|
|
67
|
+
// src/commands/auth-login.ts
|
|
68
|
+
var auth_login_exports = {};
|
|
69
|
+
__export(auth_login_exports, {
|
|
70
|
+
authLogin: () => authLogin
|
|
71
|
+
});
|
|
72
|
+
function openBrowser(url2) {
|
|
73
|
+
const cmd = (0, import_node_os.platform)() === "darwin" ? "open" : (0, import_node_os.platform)() === "win32" ? "start" : "xdg-open";
|
|
74
|
+
try {
|
|
75
|
+
(0, import_node_child_process.exec)(`${cmd} ${JSON.stringify(url2)}`);
|
|
76
|
+
return true;
|
|
77
|
+
} catch {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function sleep(ms) {
|
|
82
|
+
return new Promise((resolve4) => setTimeout(resolve4, ms));
|
|
83
|
+
}
|
|
84
|
+
async function authLogin() {
|
|
85
|
+
const apiUrl = process.env.HAANSI_API_URL ?? DEFAULT_API_URL;
|
|
86
|
+
console.log("Haansi CLI \u2014 Browser Login\n");
|
|
87
|
+
const initiateRes = await fetch(`${apiUrl}/api/v1/auth/extension/initiate`, {
|
|
88
|
+
method: "POST",
|
|
89
|
+
headers: { "Content-Type": "application/json" }
|
|
90
|
+
});
|
|
91
|
+
if (!initiateRes.ok) {
|
|
92
|
+
const body = await initiateRes.text().catch(() => "");
|
|
93
|
+
throw new Error(
|
|
94
|
+
`Failed to start auth session (${initiateRes.status}): ${body.slice(0, 200)}`
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
const { session_id, auth_url: vsCodeAuthUrl } = await initiateRes.json();
|
|
98
|
+
const frontendOrigin = new URL(vsCodeAuthUrl).origin;
|
|
99
|
+
const authUrl = `${frontendOrigin}/auth/cli?session_id=${session_id}`;
|
|
100
|
+
const opened = openBrowser(authUrl);
|
|
101
|
+
if (opened) {
|
|
102
|
+
console.log("A browser window has been opened for you to log in.");
|
|
103
|
+
} else {
|
|
104
|
+
console.log("Could not open browser automatically.");
|
|
105
|
+
}
|
|
106
|
+
console.log(`
|
|
107
|
+
If the browser didn't open, visit this URL:
|
|
108
|
+
${authUrl}
|
|
109
|
+
`);
|
|
110
|
+
console.log("Waiting for approval...");
|
|
111
|
+
const deadline = Date.now() + TIMEOUT_MS;
|
|
112
|
+
let jwt2 = null;
|
|
113
|
+
let orgName = null;
|
|
114
|
+
while (Date.now() < deadline) {
|
|
115
|
+
await sleep(POLL_INTERVAL_MS);
|
|
116
|
+
const pollRes = await fetch(
|
|
117
|
+
`${apiUrl}/api/v1/auth/extension/token?session_id=${encodeURIComponent(session_id)}`
|
|
118
|
+
);
|
|
119
|
+
if (pollRes.status === 410) {
|
|
120
|
+
throw new Error("Session expired or was already used. Please try again.");
|
|
121
|
+
}
|
|
122
|
+
if (!pollRes.ok && pollRes.status !== 200) {
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
const data = await pollRes.json();
|
|
126
|
+
if (data.status === "pending") {
|
|
127
|
+
process.stdout.write(".");
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
if (data.token) {
|
|
131
|
+
jwt2 = data.token;
|
|
132
|
+
orgName = data.organization?.name ?? null;
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
console.log("");
|
|
137
|
+
if (!jwt2) {
|
|
138
|
+
throw new Error(
|
|
139
|
+
"Timed out waiting for approval. You can authenticate manually with `haansi init`."
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
console.log("Creating CLI token...");
|
|
143
|
+
const tokenRes = await fetch(`${apiUrl}/api/v1/cli-tokens`, {
|
|
144
|
+
method: "POST",
|
|
145
|
+
headers: {
|
|
146
|
+
Authorization: `Bearer ${jwt2}`,
|
|
147
|
+
"Content-Type": "application/json"
|
|
148
|
+
},
|
|
149
|
+
body: JSON.stringify({ name: "CLI (haansi auth login)" })
|
|
150
|
+
});
|
|
151
|
+
if (!tokenRes.ok) {
|
|
152
|
+
const body = await tokenRes.text().catch(() => "");
|
|
153
|
+
throw new Error(
|
|
154
|
+
`Failed to create CLI token (${tokenRes.status}): ${body.slice(0, 200)}`
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
const { token: hskToken } = await tokenRes.json();
|
|
158
|
+
(0, import_node_fs.mkdirSync)(HAANSI_DIR, { recursive: true });
|
|
159
|
+
(0, import_node_fs.writeFileSync)(
|
|
160
|
+
CREDENTIALS_FILE,
|
|
161
|
+
JSON.stringify({ token: hskToken }, null, 2),
|
|
162
|
+
{
|
|
163
|
+
encoding: "utf-8",
|
|
164
|
+
mode: 384
|
|
165
|
+
}
|
|
166
|
+
);
|
|
167
|
+
console.log(`
|
|
168
|
+
Authenticated successfully${orgName ? ` (${orgName})` : ""}!`);
|
|
169
|
+
console.log(`Token saved to ${CREDENTIALS_FILE}`);
|
|
170
|
+
console.log(
|
|
171
|
+
"Run `haansi collect` to upload sessions or `haansi setup-mcp` to configure Claude Code."
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
var import_node_child_process, import_node_fs, import_node_path, import_node_os, DEFAULT_API_URL, HAANSI_DIR, CREDENTIALS_FILE, POLL_INTERVAL_MS, TIMEOUT_MS;
|
|
175
|
+
var init_auth_login = __esm({
|
|
176
|
+
"src/commands/auth-login.ts"() {
|
|
177
|
+
"use strict";
|
|
178
|
+
import_node_child_process = require("node:child_process");
|
|
179
|
+
import_node_fs = require("node:fs");
|
|
180
|
+
import_node_path = require("node:path");
|
|
181
|
+
import_node_os = require("node:os");
|
|
182
|
+
DEFAULT_API_URL = "https://api.haansi.co";
|
|
183
|
+
HAANSI_DIR = (0, import_node_path.join)((0, import_node_os.homedir)(), ".haansi");
|
|
184
|
+
CREDENTIALS_FILE = (0, import_node_path.join)(HAANSI_DIR, "credentials.json");
|
|
185
|
+
POLL_INTERVAL_MS = 2e3;
|
|
186
|
+
TIMEOUT_MS = 5 * 60 * 1e3;
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
|
|
67
190
|
// src/commands/init.ts
|
|
68
191
|
var init_exports = {};
|
|
69
192
|
__export(init_exports, {
|
|
@@ -93,8 +216,11 @@ async function validateToken(token, apiUrl) {
|
|
|
93
216
|
}
|
|
94
217
|
}
|
|
95
218
|
async function init() {
|
|
96
|
-
const apiUrl = process.env.HAANSI_API_URL ??
|
|
219
|
+
const apiUrl = process.env.HAANSI_API_URL ?? DEFAULT_API_URL2;
|
|
97
220
|
console.log("Haansi CLI \u2014 Setup\n");
|
|
221
|
+
console.log(
|
|
222
|
+
"Tip: For interactive login, run `haansi auth login` to authenticate via browser.\n"
|
|
223
|
+
);
|
|
98
224
|
console.log(
|
|
99
225
|
`You can generate an API token at https://app.haansi.co/settings/tokens
|
|
100
226
|
`
|
|
@@ -110,28 +236,28 @@ async function init() {
|
|
|
110
236
|
}
|
|
111
237
|
console.log("\nValidating token...");
|
|
112
238
|
await validateToken(token, apiUrl);
|
|
113
|
-
(0,
|
|
114
|
-
(0,
|
|
239
|
+
(0, import_node_fs2.mkdirSync)(HAANSI_DIR2, { recursive: true });
|
|
240
|
+
(0, import_node_fs2.writeFileSync)(CREDENTIALS_FILE2, JSON.stringify({ token }, null, 2), {
|
|
115
241
|
encoding: "utf-8",
|
|
116
242
|
mode: 384
|
|
117
243
|
});
|
|
118
244
|
console.log(`
|
|
119
|
-
Token saved to ${
|
|
245
|
+
Token saved to ${CREDENTIALS_FILE2}`);
|
|
120
246
|
console.log(
|
|
121
247
|
"Run `haansi daemon` to start collecting or `haansi setup-mcp` to configure Claude Code."
|
|
122
248
|
);
|
|
123
249
|
}
|
|
124
|
-
var readline,
|
|
250
|
+
var readline, import_node_fs2, import_node_path2, import_node_os2, DEFAULT_API_URL2, HAANSI_DIR2, CREDENTIALS_FILE2;
|
|
125
251
|
var init_init = __esm({
|
|
126
252
|
"src/commands/init.ts"() {
|
|
127
253
|
"use strict";
|
|
128
254
|
readline = __toESM(require("node:readline"));
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
255
|
+
import_node_fs2 = require("node:fs");
|
|
256
|
+
import_node_path2 = require("node:path");
|
|
257
|
+
import_node_os2 = require("node:os");
|
|
258
|
+
DEFAULT_API_URL2 = "https://api.haansi.co";
|
|
259
|
+
HAANSI_DIR2 = (0, import_node_path2.join)((0, import_node_os2.homedir)(), ".haansi");
|
|
260
|
+
CREDENTIALS_FILE2 = (0, import_node_path2.join)(HAANSI_DIR2, "credentials.json");
|
|
135
261
|
}
|
|
136
262
|
});
|
|
137
263
|
|
|
@@ -636,13 +762,13 @@ function extractSessionMeta(filePath) {
|
|
|
636
762
|
}
|
|
637
763
|
function resolveToken() {
|
|
638
764
|
if (process.env.HAANSI_TOKEN) return process.env.HAANSI_TOKEN;
|
|
639
|
-
if ((0, import_fs.existsSync)(
|
|
765
|
+
if ((0, import_fs.existsSync)(CREDENTIALS_FILE3)) {
|
|
640
766
|
try {
|
|
641
|
-
const creds = JSON.parse((0, import_fs.readFileSync)(
|
|
767
|
+
const creds = JSON.parse((0, import_fs.readFileSync)(CREDENTIALS_FILE3, "utf-8"));
|
|
642
768
|
if (creds.token) return creds.token;
|
|
643
769
|
} catch {
|
|
644
770
|
logger.warn("Could not parse credentials file", {
|
|
645
|
-
file:
|
|
771
|
+
file: CREDENTIALS_FILE3
|
|
646
772
|
});
|
|
647
773
|
}
|
|
648
774
|
}
|
|
@@ -731,7 +857,7 @@ async function uploadSession(sessionId, content, apiUrl, token, gitInfo) {
|
|
|
731
857
|
}
|
|
732
858
|
}
|
|
733
859
|
async function collect(options) {
|
|
734
|
-
const apiUrl = process.env.HAANSI_API_URL ??
|
|
860
|
+
const apiUrl = process.env.HAANSI_API_URL ?? DEFAULT_API_URL3;
|
|
735
861
|
const token = resolveToken();
|
|
736
862
|
if (!token && !options.dryRun) {
|
|
737
863
|
throw new Error(
|
|
@@ -813,7 +939,7 @@ async function main() {
|
|
|
813
939
|
});
|
|
814
940
|
if (errors > 0) process.exit(1);
|
|
815
941
|
}
|
|
816
|
-
var import_dotenv, import_path, import_fs, import_os, import_zlib, import_child_process, logger,
|
|
942
|
+
var import_dotenv, import_path, import_fs, import_os, import_zlib, import_child_process, logger, DEFAULT_API_URL3, CREDENTIALS_FILE3, CLAUDE_PROJECTS_DIR, MIN_LINES, EDGE_SCRUB_PATTERNS;
|
|
817
943
|
var init_collector = __esm({
|
|
818
944
|
"../service-capture/claude-sessions/collector.ts"() {
|
|
819
945
|
"use strict";
|
|
@@ -826,8 +952,8 @@ var init_collector = __esm({
|
|
|
826
952
|
init_logger();
|
|
827
953
|
(0, import_dotenv.config)({ path: (0, import_path.resolve)(__dirname, "../../../.env") });
|
|
828
954
|
logger = createLogger("claude-collector");
|
|
829
|
-
|
|
830
|
-
|
|
955
|
+
DEFAULT_API_URL3 = "https://api.haansi.co";
|
|
956
|
+
CREDENTIALS_FILE3 = (0, import_path.join)((0, import_os.homedir)(), ".haansi", "credentials.json");
|
|
831
957
|
CLAUDE_PROJECTS_DIR = (0, import_path.join)((0, import_os.homedir)(), ".claude", "projects");
|
|
832
958
|
MIN_LINES = 4;
|
|
833
959
|
EDGE_SCRUB_PATTERNS = [
|
|
@@ -892,17 +1018,17 @@ var require_task = __commonJS({
|
|
|
892
1018
|
this._execution = execution;
|
|
893
1019
|
}
|
|
894
1020
|
execute(now) {
|
|
895
|
-
let
|
|
1021
|
+
let exec2;
|
|
896
1022
|
try {
|
|
897
|
-
|
|
1023
|
+
exec2 = this._execution(now);
|
|
898
1024
|
} catch (error2) {
|
|
899
1025
|
return this.emit("task-failed", error2);
|
|
900
1026
|
}
|
|
901
|
-
if (
|
|
902
|
-
return
|
|
1027
|
+
if (exec2 instanceof Promise) {
|
|
1028
|
+
return exec2.then(() => this.emit("task-finished")).catch((error2) => this.emit("task-failed", error2));
|
|
903
1029
|
} else {
|
|
904
1030
|
this.emit("task-finished");
|
|
905
|
-
return
|
|
1031
|
+
return exec2;
|
|
906
1032
|
}
|
|
907
1033
|
}
|
|
908
1034
|
};
|
|
@@ -50545,7 +50671,7 @@ var require_view = __commonJS({
|
|
|
50545
50671
|
var dirname = path.dirname;
|
|
50546
50672
|
var basename2 = path.basename;
|
|
50547
50673
|
var extname = path.extname;
|
|
50548
|
-
var
|
|
50674
|
+
var join9 = path.join;
|
|
50549
50675
|
var resolve4 = path.resolve;
|
|
50550
50676
|
module2.exports = View;
|
|
50551
50677
|
function View(name, options) {
|
|
@@ -50607,12 +50733,12 @@ var require_view = __commonJS({
|
|
|
50607
50733
|
};
|
|
50608
50734
|
View.prototype.resolve = function resolve5(dir, file2) {
|
|
50609
50735
|
var ext = this.ext;
|
|
50610
|
-
var path2 =
|
|
50736
|
+
var path2 = join9(dir, file2);
|
|
50611
50737
|
var stat = tryStat(path2);
|
|
50612
50738
|
if (stat && stat.isFile()) {
|
|
50613
50739
|
return path2;
|
|
50614
50740
|
}
|
|
50615
|
-
path2 =
|
|
50741
|
+
path2 = join9(dir, basename2(file2, ext), "index" + ext);
|
|
50616
50742
|
stat = tryStat(path2);
|
|
50617
50743
|
if (stat && stat.isFile()) {
|
|
50618
50744
|
return path2;
|
|
@@ -54257,7 +54383,7 @@ var require_send = __commonJS({
|
|
|
54257
54383
|
var Stream = require("stream");
|
|
54258
54384
|
var util2 = require("util");
|
|
54259
54385
|
var extname = path.extname;
|
|
54260
|
-
var
|
|
54386
|
+
var join9 = path.join;
|
|
54261
54387
|
var normalize = path.normalize;
|
|
54262
54388
|
var resolve4 = path.resolve;
|
|
54263
54389
|
var sep = path.sep;
|
|
@@ -54429,7 +54555,7 @@ var require_send = __commonJS({
|
|
|
54429
54555
|
return res;
|
|
54430
54556
|
}
|
|
54431
54557
|
parts = path2.split(sep);
|
|
54432
|
-
path2 = normalize(
|
|
54558
|
+
path2 = normalize(join9(root, path2));
|
|
54433
54559
|
} else {
|
|
54434
54560
|
if (UP_PATH_REGEXP.test(path2)) {
|
|
54435
54561
|
debug('malicious path "%s"', path2);
|
|
@@ -54562,7 +54688,7 @@ var require_send = __commonJS({
|
|
|
54562
54688
|
if (err) return self.onStatError(err);
|
|
54563
54689
|
return self.error(404);
|
|
54564
54690
|
}
|
|
54565
|
-
var p =
|
|
54691
|
+
var p = join9(path2, self._index[i]);
|
|
54566
54692
|
debug('stat "%s"', p);
|
|
54567
54693
|
fs.stat(p, function(err2, stat) {
|
|
54568
54694
|
if (err2) return next(err2);
|
|
@@ -56659,9 +56785,9 @@ var init_streamableHttp = __esm({
|
|
|
56659
56785
|
var mcp_server_exports = {};
|
|
56660
56786
|
function resolveToken2() {
|
|
56661
56787
|
if (process.env.HAANSI_TOKEN) return process.env.HAANSI_TOKEN;
|
|
56662
|
-
if ((0, import_fs2.existsSync)(
|
|
56788
|
+
if ((0, import_fs2.existsSync)(CREDENTIALS_FILE4)) {
|
|
56663
56789
|
try {
|
|
56664
|
-
const creds = JSON.parse((0, import_fs2.readFileSync)(
|
|
56790
|
+
const creds = JSON.parse((0, import_fs2.readFileSync)(CREDENTIALS_FILE4, "utf-8"));
|
|
56665
56791
|
if (creds.token) return creds.token;
|
|
56666
56792
|
} catch {
|
|
56667
56793
|
}
|
|
@@ -56745,7 +56871,7 @@ async function main3() {
|
|
|
56745
56871
|
await mcpServer.connect(transport);
|
|
56746
56872
|
}
|
|
56747
56873
|
}
|
|
56748
|
-
var import_dotenv3, import_path3, import_fs2, import_os2,
|
|
56874
|
+
var import_dotenv3, import_path3, import_fs2, import_os2, DEFAULT_API_URL4, CREDENTIALS_FILE4, API_URL, TOKEN, contextSchema, isCollecting, lastCollectTime, COLLECT_COOLDOWN_MS, mcpServer, server;
|
|
56749
56875
|
var init_mcp_server2 = __esm({
|
|
56750
56876
|
"../service-capture/claude-sessions/mcp-server.ts"() {
|
|
56751
56877
|
"use strict";
|
|
@@ -56759,9 +56885,9 @@ var init_mcp_server2 = __esm({
|
|
|
56759
56885
|
init_stdio2();
|
|
56760
56886
|
init_types2();
|
|
56761
56887
|
(0, import_dotenv3.config)({ path: (0, import_path3.resolve)(__dirname, "../../../.env") });
|
|
56762
|
-
|
|
56763
|
-
|
|
56764
|
-
API_URL = process.env.HAANSI_API_URL ??
|
|
56888
|
+
DEFAULT_API_URL4 = "https://api.haansi.co";
|
|
56889
|
+
CREDENTIALS_FILE4 = (0, import_path3.join)((0, import_os2.homedir)(), ".haansi", "credentials.json");
|
|
56890
|
+
API_URL = process.env.HAANSI_API_URL ?? DEFAULT_API_URL4;
|
|
56765
56891
|
TOKEN = resolveToken2();
|
|
56766
56892
|
if (!TOKEN) {
|
|
56767
56893
|
process.exit(1);
|
|
@@ -56791,7 +56917,7 @@ var init_mcp_server2 = __esm({
|
|
|
56791
56917
|
tools: [
|
|
56792
56918
|
{
|
|
56793
56919
|
name: "search_solutions",
|
|
56794
|
-
description: "
|
|
56920
|
+
description: "Search previously solved similar questions from your organization's knowledge base. Finds how bugs were fixed, what patterns were used, and past resolutions to similar problems. Results are ranked by a composite of relevance, quality, recency, and verification status.",
|
|
56795
56921
|
inputSchema: {
|
|
56796
56922
|
type: "object",
|
|
56797
56923
|
properties: {
|
|
@@ -56943,8 +57069,13 @@ var init_mcp_server2 = __esm({
|
|
|
56943
57069
|
]
|
|
56944
57070
|
};
|
|
56945
57071
|
}
|
|
57072
|
+
const header = `Found ${data.total} answer(s) from similar questions in your organization:
|
|
57073
|
+
|
|
57074
|
+
`;
|
|
56946
57075
|
return {
|
|
56947
|
-
content: [
|
|
57076
|
+
content: [
|
|
57077
|
+
{ type: "text", text: header + data.results.join("\n\n---\n\n") }
|
|
57078
|
+
]
|
|
56948
57079
|
};
|
|
56949
57080
|
}
|
|
56950
57081
|
case "list_recent_solutions": {
|
|
@@ -57056,7 +57187,7 @@ __export(setup_mcp_exports, {
|
|
|
57056
57187
|
});
|
|
57057
57188
|
function resolveHaansiBin() {
|
|
57058
57189
|
try {
|
|
57059
|
-
const binPath = (0,
|
|
57190
|
+
const binPath = (0, import_node_child_process2.execSync)("which haansi", { encoding: "utf-8" }).trim();
|
|
57060
57191
|
if (binPath) return binPath;
|
|
57061
57192
|
} catch {
|
|
57062
57193
|
}
|
|
@@ -57064,9 +57195,9 @@ function resolveHaansiBin() {
|
|
|
57064
57195
|
}
|
|
57065
57196
|
async function setupMcp() {
|
|
57066
57197
|
let config6 = {};
|
|
57067
|
-
if ((0,
|
|
57198
|
+
if ((0, import_node_fs3.existsSync)(CLAUDE_JSON)) {
|
|
57068
57199
|
try {
|
|
57069
|
-
config6 = JSON.parse((0,
|
|
57200
|
+
config6 = JSON.parse((0, import_node_fs3.readFileSync)(CLAUDE_JSON, "utf-8"));
|
|
57070
57201
|
} catch {
|
|
57071
57202
|
console.error(
|
|
57072
57203
|
`Warning: Could not parse ${CLAUDE_JSON} \u2014 will overwrite with new config.`
|
|
@@ -57081,22 +57212,22 @@ async function setupMcp() {
|
|
|
57081
57212
|
command: haansiBin,
|
|
57082
57213
|
args: ["mcp-server"]
|
|
57083
57214
|
};
|
|
57084
|
-
(0,
|
|
57215
|
+
(0, import_node_fs3.writeFileSync)(CLAUDE_JSON, JSON.stringify(config6, null, 2) + "\n", "utf-8");
|
|
57085
57216
|
console.log(`MCP server configured in ${CLAUDE_JSON}`);
|
|
57086
57217
|
console.log(` command: ${haansiBin} mcp-server`);
|
|
57087
57218
|
console.log(
|
|
57088
57219
|
"\nRestart Claude Code to activate the haansi-solutions MCP server."
|
|
57089
57220
|
);
|
|
57090
57221
|
}
|
|
57091
|
-
var
|
|
57222
|
+
var import_node_fs3, import_node_path3, import_node_os3, import_node_child_process2, CLAUDE_JSON;
|
|
57092
57223
|
var init_setup_mcp = __esm({
|
|
57093
57224
|
"src/commands/setup-mcp.ts"() {
|
|
57094
57225
|
"use strict";
|
|
57095
|
-
|
|
57096
|
-
|
|
57097
|
-
|
|
57098
|
-
|
|
57099
|
-
CLAUDE_JSON = (0,
|
|
57226
|
+
import_node_fs3 = require("node:fs");
|
|
57227
|
+
import_node_path3 = require("node:path");
|
|
57228
|
+
import_node_os3 = require("node:os");
|
|
57229
|
+
import_node_child_process2 = require("node:child_process");
|
|
57230
|
+
CLAUDE_JSON = (0, import_node_path3.join)((0, import_node_os3.homedir)(), ".claude.json");
|
|
57100
57231
|
}
|
|
57101
57232
|
});
|
|
57102
57233
|
|
|
@@ -57107,7 +57238,7 @@ __export(setup_daemon_exports, {
|
|
|
57107
57238
|
});
|
|
57108
57239
|
function findHaansiBin() {
|
|
57109
57240
|
try {
|
|
57110
|
-
return (0,
|
|
57241
|
+
return (0, import_node_child_process3.execSync)("which haansi", { encoding: "utf-8" }).trim();
|
|
57111
57242
|
} catch {
|
|
57112
57243
|
throw new Error(
|
|
57113
57244
|
"Could not find haansi in PATH. Make sure it is installed globally (npm install -g haansi)."
|
|
@@ -57146,28 +57277,28 @@ function buildPlist(haansiPath) {
|
|
|
57146
57277
|
}
|
|
57147
57278
|
async function setupDaemon(uninstall) {
|
|
57148
57279
|
if (uninstall) {
|
|
57149
|
-
if (!(0,
|
|
57280
|
+
if (!(0, import_node_fs4.existsSync)(PLIST_PATH)) {
|
|
57150
57281
|
console.log("Daemon is not installed.");
|
|
57151
57282
|
return;
|
|
57152
57283
|
}
|
|
57153
57284
|
try {
|
|
57154
|
-
(0,
|
|
57285
|
+
(0, import_node_child_process3.spawnSync)("launchctl", ["unload", PLIST_PATH], { stdio: "pipe" });
|
|
57155
57286
|
} catch (err) {
|
|
57156
57287
|
console.error("Failed to unload daemon:", err);
|
|
57157
57288
|
}
|
|
57158
|
-
(0,
|
|
57289
|
+
(0, import_node_fs4.unlinkSync)(PLIST_PATH);
|
|
57159
57290
|
console.log("Daemon stopped and removed.");
|
|
57160
57291
|
return;
|
|
57161
57292
|
}
|
|
57162
57293
|
const haansiPath = findHaansiBin();
|
|
57163
|
-
(0,
|
|
57164
|
-
(0,
|
|
57294
|
+
(0, import_node_fs4.mkdirSync)((0, import_node_path4.join)((0, import_node_os4.homedir)(), ".haansi"), { recursive: true });
|
|
57295
|
+
(0, import_node_fs4.writeFileSync)(PLIST_PATH, buildPlist(haansiPath), "utf-8");
|
|
57165
57296
|
try {
|
|
57166
|
-
(0,
|
|
57297
|
+
(0, import_node_child_process3.spawnSync)("launchctl", ["unload", PLIST_PATH], { stdio: "pipe" });
|
|
57167
57298
|
} catch (err) {
|
|
57168
57299
|
console.error("Failed to unload previous daemon:", err);
|
|
57169
57300
|
}
|
|
57170
|
-
(0,
|
|
57301
|
+
(0, import_node_child_process3.spawnSync)("launchctl", ["load", PLIST_PATH], { stdio: "inherit" });
|
|
57171
57302
|
console.log("Daemon installed and started.");
|
|
57172
57303
|
console.log(`Plist : ${PLIST_PATH}`);
|
|
57173
57304
|
console.log(`Logs : ${LOG_FILE}`);
|
|
@@ -57175,22 +57306,22 @@ async function setupDaemon(uninstall) {
|
|
|
57175
57306
|
The daemon will start automatically on every login.`);
|
|
57176
57307
|
console.log(`To uninstall: haansi setup-daemon --uninstall`);
|
|
57177
57308
|
}
|
|
57178
|
-
var
|
|
57309
|
+
var import_node_child_process3, import_node_fs4, import_node_path4, import_node_os4, PLIST_LABEL, PLIST_PATH, LOG_FILE;
|
|
57179
57310
|
var init_setup_daemon = __esm({
|
|
57180
57311
|
"src/commands/setup-daemon.ts"() {
|
|
57181
57312
|
"use strict";
|
|
57182
|
-
|
|
57183
|
-
|
|
57184
|
-
|
|
57185
|
-
|
|
57313
|
+
import_node_child_process3 = require("node:child_process");
|
|
57314
|
+
import_node_fs4 = require("node:fs");
|
|
57315
|
+
import_node_path4 = require("node:path");
|
|
57316
|
+
import_node_os4 = require("node:os");
|
|
57186
57317
|
PLIST_LABEL = "co.haansi.daemon";
|
|
57187
|
-
PLIST_PATH = (0,
|
|
57188
|
-
(0,
|
|
57318
|
+
PLIST_PATH = (0, import_node_path4.join)(
|
|
57319
|
+
(0, import_node_os4.homedir)(),
|
|
57189
57320
|
"Library",
|
|
57190
57321
|
"LaunchAgents",
|
|
57191
57322
|
`${PLIST_LABEL}.plist`
|
|
57192
57323
|
);
|
|
57193
|
-
LOG_FILE = (0,
|
|
57324
|
+
LOG_FILE = (0, import_node_path4.join)((0, import_node_os4.homedir)(), ".haansi", "daemon.log");
|
|
57194
57325
|
}
|
|
57195
57326
|
});
|
|
57196
57327
|
|
|
@@ -57201,9 +57332,9 @@ __export(config_exports, {
|
|
|
57201
57332
|
});
|
|
57202
57333
|
function resolveToken3() {
|
|
57203
57334
|
if (process.env.HAANSI_TOKEN) return process.env.HAANSI_TOKEN;
|
|
57204
|
-
if ((0,
|
|
57335
|
+
if ((0, import_node_fs5.existsSync)(CREDENTIALS_FILE5)) {
|
|
57205
57336
|
try {
|
|
57206
|
-
const creds = JSON.parse((0,
|
|
57337
|
+
const creds = JSON.parse((0, import_node_fs5.readFileSync)(CREDENTIALS_FILE5, "utf-8"));
|
|
57207
57338
|
if (creds.token) return creds.token;
|
|
57208
57339
|
} catch (err) {
|
|
57209
57340
|
console.error("Failed to read credentials file:", err);
|
|
@@ -57220,7 +57351,7 @@ async function config5(args) {
|
|
|
57220
57351
|
process.exit(1);
|
|
57221
57352
|
return;
|
|
57222
57353
|
}
|
|
57223
|
-
const apiUrl = process.env.HAANSI_API_URL ??
|
|
57354
|
+
const apiUrl = process.env.HAANSI_API_URL ?? DEFAULT_API_URL5;
|
|
57224
57355
|
const subcommand = args[0];
|
|
57225
57356
|
if (subcommand === "get") {
|
|
57226
57357
|
const key = args[1];
|
|
@@ -57295,15 +57426,15 @@ Supported keys:
|
|
|
57295
57426
|
if (subcommand !== void 0) process.exit(1);
|
|
57296
57427
|
}
|
|
57297
57428
|
}
|
|
57298
|
-
var
|
|
57429
|
+
var import_node_fs5, import_node_path5, import_node_os5, DEFAULT_API_URL5, CREDENTIALS_FILE5, VALID_SESSION_MODES;
|
|
57299
57430
|
var init_config = __esm({
|
|
57300
57431
|
"src/commands/config.ts"() {
|
|
57301
57432
|
"use strict";
|
|
57302
|
-
|
|
57303
|
-
|
|
57304
|
-
|
|
57305
|
-
|
|
57306
|
-
|
|
57433
|
+
import_node_fs5 = require("node:fs");
|
|
57434
|
+
import_node_path5 = require("node:path");
|
|
57435
|
+
import_node_os5 = require("node:os");
|
|
57436
|
+
DEFAULT_API_URL5 = "https://api.haansi.co";
|
|
57437
|
+
CREDENTIALS_FILE5 = (0, import_node_path5.join)((0, import_node_os5.homedir)(), ".haansi", "credentials.json");
|
|
57307
57438
|
VALID_SESSION_MODES = ["private", "org"];
|
|
57308
57439
|
}
|
|
57309
57440
|
});
|
|
@@ -57317,9 +57448,9 @@ __export(list_exports, {
|
|
|
57317
57448
|
});
|
|
57318
57449
|
function resolveToken4() {
|
|
57319
57450
|
if (process.env.HAANSI_TOKEN) return process.env.HAANSI_TOKEN;
|
|
57320
|
-
if ((0,
|
|
57451
|
+
if ((0, import_node_fs6.existsSync)(CREDENTIALS_FILE6)) {
|
|
57321
57452
|
try {
|
|
57322
|
-
const creds = JSON.parse((0,
|
|
57453
|
+
const creds = JSON.parse((0, import_node_fs6.readFileSync)(CREDENTIALS_FILE6, "utf-8"));
|
|
57323
57454
|
if (creds.token) return creds.token;
|
|
57324
57455
|
} catch (err) {
|
|
57325
57456
|
console.error("Failed to read credentials file:", err);
|
|
@@ -57353,7 +57484,7 @@ async function apiPost2(path, body, token, apiUrl) {
|
|
|
57353
57484
|
return response.json();
|
|
57354
57485
|
}
|
|
57355
57486
|
async function list(options) {
|
|
57356
|
-
const apiUrl = process.env.HAANSI_API_URL ??
|
|
57487
|
+
const apiUrl = process.env.HAANSI_API_URL ?? DEFAULT_API_URL6;
|
|
57357
57488
|
const token = resolveToken4();
|
|
57358
57489
|
let data;
|
|
57359
57490
|
if (options.search) {
|
|
@@ -57379,7 +57510,7 @@ async function list(options) {
|
|
|
57379
57510
|
${data.results.length} result(s)`);
|
|
57380
57511
|
}
|
|
57381
57512
|
async function searchKnowledge(options) {
|
|
57382
|
-
const apiUrl = process.env.HAANSI_API_URL ??
|
|
57513
|
+
const apiUrl = process.env.HAANSI_API_URL ?? DEFAULT_API_URL6;
|
|
57383
57514
|
const token = resolveToken4();
|
|
57384
57515
|
let url2 = `/sessions/knowledge/search?q=${encodeURIComponent(options.query)}&limit=${options.limit}`;
|
|
57385
57516
|
if (options.artifactType) {
|
|
@@ -57396,7 +57527,7 @@ async function searchKnowledge(options) {
|
|
|
57396
57527
|
${data.results.length} result(s)`);
|
|
57397
57528
|
}
|
|
57398
57529
|
async function saveKnowledge(options) {
|
|
57399
|
-
const apiUrl = process.env.HAANSI_API_URL ??
|
|
57530
|
+
const apiUrl = process.env.HAANSI_API_URL ?? DEFAULT_API_URL6;
|
|
57400
57531
|
const token = resolveToken4();
|
|
57401
57532
|
const body = {
|
|
57402
57533
|
problem_description: options.problem,
|
|
@@ -57412,15 +57543,15 @@ async function saveKnowledge(options) {
|
|
|
57412
57543
|
console.log(` Solution: ${data.solution_summary}`);
|
|
57413
57544
|
console.log("\nThis is now searchable via `haansi search-solutions`.");
|
|
57414
57545
|
}
|
|
57415
|
-
var
|
|
57546
|
+
var import_node_fs6, import_node_path6, import_node_os6, DEFAULT_API_URL6, CREDENTIALS_FILE6;
|
|
57416
57547
|
var init_list = __esm({
|
|
57417
57548
|
"src/commands/list.ts"() {
|
|
57418
57549
|
"use strict";
|
|
57419
|
-
|
|
57420
|
-
|
|
57421
|
-
|
|
57422
|
-
|
|
57423
|
-
|
|
57550
|
+
import_node_fs6 = require("node:fs");
|
|
57551
|
+
import_node_path6 = require("node:path");
|
|
57552
|
+
import_node_os6 = require("node:os");
|
|
57553
|
+
DEFAULT_API_URL6 = "https://api.haansi.co";
|
|
57554
|
+
CREDENTIALS_FILE6 = (0, import_node_path6.join)((0, import_node_os6.homedir)(), ".haansi", "credentials.json");
|
|
57424
57555
|
}
|
|
57425
57556
|
});
|
|
57426
57557
|
|
|
@@ -57433,6 +57564,20 @@ async function run2() {
|
|
|
57433
57564
|
return;
|
|
57434
57565
|
}
|
|
57435
57566
|
switch (command) {
|
|
57567
|
+
case "auth": {
|
|
57568
|
+
const subcommand = process.argv[3];
|
|
57569
|
+
if (subcommand === "login") {
|
|
57570
|
+
const { authLogin: authLogin2 } = await Promise.resolve().then(() => (init_auth_login(), auth_login_exports));
|
|
57571
|
+
await authLogin2();
|
|
57572
|
+
} else {
|
|
57573
|
+
console.error(
|
|
57574
|
+
`Unknown auth subcommand: ${subcommand ?? "(none)"}
|
|
57575
|
+
Usage: haansi auth login`
|
|
57576
|
+
);
|
|
57577
|
+
process.exit(1);
|
|
57578
|
+
}
|
|
57579
|
+
break;
|
|
57580
|
+
}
|
|
57436
57581
|
case "init": {
|
|
57437
57582
|
const { init: init2 } = await Promise.resolve().then(() => (init_init(), init_exports));
|
|
57438
57583
|
await init2();
|
|
@@ -57559,7 +57704,8 @@ Usage:
|
|
|
57559
57704
|
haansi <command> [options]
|
|
57560
57705
|
|
|
57561
57706
|
Commands:
|
|
57562
|
-
|
|
57707
|
+
auth login Log in via browser (recommended)
|
|
57708
|
+
init Authenticate with a token (for CI / headless)
|
|
57563
57709
|
collect Upload new/changed Claude sessions once
|
|
57564
57710
|
config get [key] Show your preferences (e.g. session_mode)
|
|
57565
57711
|
config set <key> <val> Update a preference
|