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