haansi 0.1.24 → 0.1.26
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/README.md +33 -19
- package/dist/haansi.js +738 -239
- package/package.json +2 -2
package/dist/haansi.js
CHANGED
|
@@ -39,8 +39,8 @@ var require_package = __commonJS({
|
|
|
39
39
|
"package.json"(exports2, module2) {
|
|
40
40
|
module2.exports = {
|
|
41
41
|
name: "haansi",
|
|
42
|
-
version: "0.1.
|
|
43
|
-
description: "Haansi CLI - Session collector and MCP server for Claude Code",
|
|
42
|
+
version: "0.1.26",
|
|
43
|
+
description: "Haansi CLI - Session collector and MCP server for Claude Code & OpenAI Codex",
|
|
44
44
|
bin: {
|
|
45
45
|
haansi: "./dist/haansi.js"
|
|
46
46
|
},
|
|
@@ -82,9 +82,9 @@ function sleep(ms) {
|
|
|
82
82
|
return new Promise((resolve4) => setTimeout(resolve4, ms));
|
|
83
83
|
}
|
|
84
84
|
async function authLogin() {
|
|
85
|
-
const
|
|
85
|
+
const apiUrl2 = process.env.HAANSI_API_URL ?? DEFAULT_API_URL;
|
|
86
86
|
console.log("Haansi CLI \u2014 Browser Login\n");
|
|
87
|
-
const initiateRes = await fetch(`${
|
|
87
|
+
const initiateRes = await fetch(`${apiUrl2}/api/v1/auth/extension/initiate`, {
|
|
88
88
|
method: "POST",
|
|
89
89
|
headers: { "Content-Type": "application/json" },
|
|
90
90
|
body: JSON.stringify({ client_type: "cli" })
|
|
@@ -115,7 +115,7 @@ If the browser didn't open, visit this URL:
|
|
|
115
115
|
while (Date.now() < deadline) {
|
|
116
116
|
await sleep(POLL_INTERVAL_MS);
|
|
117
117
|
const pollRes = await fetch(
|
|
118
|
-
`${
|
|
118
|
+
`${apiUrl2}/api/v1/auth/extension/token?session_id=${encodeURIComponent(session_id)}`
|
|
119
119
|
);
|
|
120
120
|
if (pollRes.status === 410) {
|
|
121
121
|
throw new Error("Session expired or was already used. Please try again.");
|
|
@@ -141,7 +141,7 @@ If the browser didn't open, visit this URL:
|
|
|
141
141
|
);
|
|
142
142
|
}
|
|
143
143
|
console.log("Creating CLI token...");
|
|
144
|
-
const tokenRes = await fetch(`${
|
|
144
|
+
const tokenRes = await fetch(`${apiUrl2}/api/v1/access/cli-tokens`, {
|
|
145
145
|
method: "POST",
|
|
146
146
|
headers: {
|
|
147
147
|
Authorization: `Bearer ${jwt2}`,
|
|
@@ -205,9 +205,9 @@ function prompt(question) {
|
|
|
205
205
|
});
|
|
206
206
|
});
|
|
207
207
|
}
|
|
208
|
-
async function validateToken(token,
|
|
208
|
+
async function validateToken(token, apiUrl2) {
|
|
209
209
|
const response = await fetch(
|
|
210
|
-
`${
|
|
210
|
+
`${apiUrl2}/api/v1/memory/solutions/recent?limit=1`,
|
|
211
211
|
{
|
|
212
212
|
headers: { Authorization: `Bearer ${token}` }
|
|
213
213
|
}
|
|
@@ -220,7 +220,7 @@ async function validateToken(token, apiUrl) {
|
|
|
220
220
|
}
|
|
221
221
|
}
|
|
222
222
|
async function init() {
|
|
223
|
-
const
|
|
223
|
+
const apiUrl2 = process.env.HAANSI_API_URL ?? DEFAULT_API_URL2;
|
|
224
224
|
console.log("Haansi CLI \u2014 Setup\n");
|
|
225
225
|
console.log(
|
|
226
226
|
"Tip: For interactive login, run `haansi auth login` to authenticate via browser.\n"
|
|
@@ -239,7 +239,7 @@ async function init() {
|
|
|
239
239
|
process.exit(1);
|
|
240
240
|
}
|
|
241
241
|
console.log("\nValidating token...");
|
|
242
|
-
await validateToken(token,
|
|
242
|
+
await validateToken(token, apiUrl2);
|
|
243
243
|
(0, import_node_fs2.mkdirSync)(HAANSI_DIR2, { recursive: true });
|
|
244
244
|
(0, import_node_fs2.writeFileSync)(CREDENTIALS_FILE2, JSON.stringify({ token }, null, 2), {
|
|
245
245
|
encoding: "utf-8",
|
|
@@ -248,7 +248,7 @@ async function init() {
|
|
|
248
248
|
console.log(`
|
|
249
249
|
Token saved to ${CREDENTIALS_FILE2}`);
|
|
250
250
|
console.log(
|
|
251
|
-
"Run `haansi daemon` to start collecting or `haansi setup-mcp` to configure Claude Code."
|
|
251
|
+
"Run `haansi daemon` to start collecting or `haansi setup-mcp` to configure your coding agent(s) (Claude Code / Codex)."
|
|
252
252
|
);
|
|
253
253
|
}
|
|
254
254
|
var readline, import_node_fs2, import_node_path2, import_node_os2, DEFAULT_API_URL2, HAANSI_DIR2, CREDENTIALS_FILE2;
|
|
@@ -675,6 +675,253 @@ var init_logger = __esm({
|
|
|
675
675
|
}
|
|
676
676
|
});
|
|
677
677
|
|
|
678
|
+
// ../service-capture/common/agents/types.ts
|
|
679
|
+
var AGENT_IDS;
|
|
680
|
+
var init_types = __esm({
|
|
681
|
+
"../service-capture/common/agents/types.ts"() {
|
|
682
|
+
"use strict";
|
|
683
|
+
AGENT_IDS = ["claude-code", "codex"];
|
|
684
|
+
}
|
|
685
|
+
});
|
|
686
|
+
|
|
687
|
+
// ../service-capture/common/agents/claude-code.ts
|
|
688
|
+
function projectsDir() {
|
|
689
|
+
return (0, import_path.join)((0, import_os.homedir)(), ".claude", "projects");
|
|
690
|
+
}
|
|
691
|
+
function extractMeta(filePath) {
|
|
692
|
+
const result = {
|
|
693
|
+
cwd: null,
|
|
694
|
+
timestamp: null,
|
|
695
|
+
gitBranch: null
|
|
696
|
+
};
|
|
697
|
+
try {
|
|
698
|
+
const lines = (0, import_fs.readFileSync)(filePath, "utf-8").split("\n").filter((l) => l.trim()).slice(0, 50);
|
|
699
|
+
for (const line of lines) {
|
|
700
|
+
try {
|
|
701
|
+
const entry = JSON.parse(line);
|
|
702
|
+
if (!result.cwd && typeof entry.cwd === "string")
|
|
703
|
+
result.cwd = entry.cwd;
|
|
704
|
+
if (!result.timestamp && typeof entry.timestamp === "string")
|
|
705
|
+
result.timestamp = entry.timestamp;
|
|
706
|
+
if (!result.gitBranch && typeof entry.gitBranch === "string")
|
|
707
|
+
result.gitBranch = entry.gitBranch;
|
|
708
|
+
if (result.cwd && result.timestamp && result.gitBranch) break;
|
|
709
|
+
} catch {
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
} catch {
|
|
713
|
+
}
|
|
714
|
+
return result;
|
|
715
|
+
}
|
|
716
|
+
var import_fs, import_path, import_os, claudeCodeAgent;
|
|
717
|
+
var init_claude_code = __esm({
|
|
718
|
+
"../service-capture/common/agents/claude-code.ts"() {
|
|
719
|
+
"use strict";
|
|
720
|
+
import_fs = require("fs");
|
|
721
|
+
import_path = require("path");
|
|
722
|
+
import_os = require("os");
|
|
723
|
+
claudeCodeAgent = {
|
|
724
|
+
id: "claude-code",
|
|
725
|
+
displayName: "Claude Code",
|
|
726
|
+
sessionsRoot() {
|
|
727
|
+
return projectsDir();
|
|
728
|
+
},
|
|
729
|
+
isInstalled() {
|
|
730
|
+
return (0, import_fs.existsSync)(projectsDir());
|
|
731
|
+
},
|
|
732
|
+
discoverSessions() {
|
|
733
|
+
const root = projectsDir();
|
|
734
|
+
if (!(0, import_fs.existsSync)(root)) return [];
|
|
735
|
+
const sessions = [];
|
|
736
|
+
const projectDirs = (0, import_fs.readdirSync)(root).map((name) => (0, import_path.join)(root, name)).filter((p) => {
|
|
737
|
+
try {
|
|
738
|
+
return (0, import_fs.statSync)(p).isDirectory();
|
|
739
|
+
} catch {
|
|
740
|
+
return false;
|
|
741
|
+
}
|
|
742
|
+
});
|
|
743
|
+
for (const dir of projectDirs) {
|
|
744
|
+
let files;
|
|
745
|
+
try {
|
|
746
|
+
files = (0, import_fs.readdirSync)(dir).filter((f) => f.endsWith(".jsonl"));
|
|
747
|
+
} catch {
|
|
748
|
+
continue;
|
|
749
|
+
}
|
|
750
|
+
for (const file2 of files) {
|
|
751
|
+
const filePath = (0, import_path.join)(dir, file2);
|
|
752
|
+
const sessionId = (0, import_path.basename)(file2, ".jsonl");
|
|
753
|
+
try {
|
|
754
|
+
const stat = (0, import_fs.statSync)(filePath);
|
|
755
|
+
const content = (0, import_fs.readFileSync)(filePath, "utf-8");
|
|
756
|
+
const lineCount = content.split("\n").filter((l) => l.trim()).length;
|
|
757
|
+
const meta3 = extractMeta(filePath);
|
|
758
|
+
sessions.push({
|
|
759
|
+
sessionId,
|
|
760
|
+
filePath,
|
|
761
|
+
lineCount,
|
|
762
|
+
sizeBytes: stat.size,
|
|
763
|
+
...meta3
|
|
764
|
+
});
|
|
765
|
+
} catch {
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
return sessions;
|
|
770
|
+
}
|
|
771
|
+
};
|
|
772
|
+
}
|
|
773
|
+
});
|
|
774
|
+
|
|
775
|
+
// ../service-capture/common/agents/codex.ts
|
|
776
|
+
function codexHome() {
|
|
777
|
+
return process.env.CODEX_HOME || (0, import_path2.join)((0, import_os2.homedir)(), ".codex");
|
|
778
|
+
}
|
|
779
|
+
function sessionsDir() {
|
|
780
|
+
return (0, import_path2.join)(codexHome(), "sessions");
|
|
781
|
+
}
|
|
782
|
+
function walkRollouts(dir, out) {
|
|
783
|
+
let entries;
|
|
784
|
+
try {
|
|
785
|
+
entries = (0, import_fs2.readdirSync)(dir);
|
|
786
|
+
} catch {
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
789
|
+
for (const name of entries) {
|
|
790
|
+
const full = (0, import_path2.join)(dir, name);
|
|
791
|
+
let isDir = false;
|
|
792
|
+
try {
|
|
793
|
+
isDir = (0, import_fs2.statSync)(full).isDirectory();
|
|
794
|
+
} catch {
|
|
795
|
+
continue;
|
|
796
|
+
}
|
|
797
|
+
if (isDir) {
|
|
798
|
+
walkRollouts(full, out);
|
|
799
|
+
} else if (name.startsWith("rollout-") && name.endsWith(".jsonl")) {
|
|
800
|
+
out.push(full);
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
function readRolloutMeta(filePath, content) {
|
|
805
|
+
const fileName = (0, import_path2.basename)(filePath, ".jsonl");
|
|
806
|
+
const fromName = UUID_RE.exec(fileName)?.[1];
|
|
807
|
+
let cwd = null;
|
|
808
|
+
let timestamp = null;
|
|
809
|
+
let gitBranch = null;
|
|
810
|
+
let metaId = null;
|
|
811
|
+
const lines = content.split("\n").filter((l) => l.trim()).slice(0, 50);
|
|
812
|
+
for (const line of lines) {
|
|
813
|
+
try {
|
|
814
|
+
const entry = JSON.parse(line);
|
|
815
|
+
if (!timestamp && typeof entry.timestamp === "string") {
|
|
816
|
+
timestamp = entry.timestamp;
|
|
817
|
+
}
|
|
818
|
+
const p = entry.payload ?? {};
|
|
819
|
+
if (entry.type === "session_meta") {
|
|
820
|
+
if (typeof p.cwd === "string") cwd = p.cwd;
|
|
821
|
+
if (typeof p.id === "string") metaId = p.id;
|
|
822
|
+
const branch = p.git?.branch ?? p.git_branch;
|
|
823
|
+
if (typeof branch === "string") gitBranch = branch;
|
|
824
|
+
}
|
|
825
|
+
if (cwd && gitBranch && timestamp && metaId) break;
|
|
826
|
+
} catch {
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
return {
|
|
830
|
+
sessionId: fromName ?? metaId ?? fileName,
|
|
831
|
+
cwd,
|
|
832
|
+
timestamp,
|
|
833
|
+
gitBranch
|
|
834
|
+
};
|
|
835
|
+
}
|
|
836
|
+
var import_fs2, import_path2, import_os2, UUID_RE, codexAgent;
|
|
837
|
+
var init_codex = __esm({
|
|
838
|
+
"../service-capture/common/agents/codex.ts"() {
|
|
839
|
+
"use strict";
|
|
840
|
+
import_fs2 = require("fs");
|
|
841
|
+
import_path2 = require("path");
|
|
842
|
+
import_os2 = require("os");
|
|
843
|
+
UUID_RE = /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/i;
|
|
844
|
+
codexAgent = {
|
|
845
|
+
id: "codex",
|
|
846
|
+
displayName: "OpenAI Codex",
|
|
847
|
+
sessionsRoot() {
|
|
848
|
+
return sessionsDir();
|
|
849
|
+
},
|
|
850
|
+
isInstalled() {
|
|
851
|
+
return (0, import_fs2.existsSync)(codexHome());
|
|
852
|
+
},
|
|
853
|
+
discoverSessions() {
|
|
854
|
+
const root = sessionsDir();
|
|
855
|
+
if (!(0, import_fs2.existsSync)(root)) return [];
|
|
856
|
+
const files = [];
|
|
857
|
+
walkRollouts(root, files);
|
|
858
|
+
const sessions = [];
|
|
859
|
+
for (const filePath of files) {
|
|
860
|
+
try {
|
|
861
|
+
const stat = (0, import_fs2.statSync)(filePath);
|
|
862
|
+
const content = (0, import_fs2.readFileSync)(filePath, "utf-8");
|
|
863
|
+
const lineCount = content.split("\n").filter((l) => l.trim()).length;
|
|
864
|
+
const meta3 = readRolloutMeta(filePath, content);
|
|
865
|
+
sessions.push({
|
|
866
|
+
sessionId: meta3.sessionId,
|
|
867
|
+
filePath,
|
|
868
|
+
lineCount,
|
|
869
|
+
sizeBytes: stat.size,
|
|
870
|
+
cwd: meta3.cwd,
|
|
871
|
+
timestamp: meta3.timestamp,
|
|
872
|
+
gitBranch: meta3.gitBranch
|
|
873
|
+
});
|
|
874
|
+
} catch {
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
return sessions;
|
|
878
|
+
}
|
|
879
|
+
};
|
|
880
|
+
}
|
|
881
|
+
});
|
|
882
|
+
|
|
883
|
+
// ../service-capture/common/agents/registry.ts
|
|
884
|
+
function getAgents() {
|
|
885
|
+
return AGENTS;
|
|
886
|
+
}
|
|
887
|
+
function getAgent(id) {
|
|
888
|
+
const agent = AGENTS.find((a) => a.id === id);
|
|
889
|
+
if (!agent) throw new Error(`Unknown agent: ${id}`);
|
|
890
|
+
return agent;
|
|
891
|
+
}
|
|
892
|
+
function detectInstalled() {
|
|
893
|
+
return AGENTS.filter((a) => a.isInstalled());
|
|
894
|
+
}
|
|
895
|
+
var AGENTS;
|
|
896
|
+
var init_registry = __esm({
|
|
897
|
+
"../service-capture/common/agents/registry.ts"() {
|
|
898
|
+
"use strict";
|
|
899
|
+
init_claude_code();
|
|
900
|
+
init_codex();
|
|
901
|
+
AGENTS = [claudeCodeAgent, codexAgent];
|
|
902
|
+
}
|
|
903
|
+
});
|
|
904
|
+
|
|
905
|
+
// ../service-capture/common/agents/index.ts
|
|
906
|
+
var agents_exports = {};
|
|
907
|
+
__export(agents_exports, {
|
|
908
|
+
AGENT_IDS: () => AGENT_IDS,
|
|
909
|
+
claudeCodeAgent: () => claudeCodeAgent,
|
|
910
|
+
codexAgent: () => codexAgent,
|
|
911
|
+
detectInstalled: () => detectInstalled,
|
|
912
|
+
getAgent: () => getAgent,
|
|
913
|
+
getAgents: () => getAgents
|
|
914
|
+
});
|
|
915
|
+
var init_agents = __esm({
|
|
916
|
+
"../service-capture/common/agents/index.ts"() {
|
|
917
|
+
"use strict";
|
|
918
|
+
init_types();
|
|
919
|
+
init_claude_code();
|
|
920
|
+
init_codex();
|
|
921
|
+
init_registry();
|
|
922
|
+
}
|
|
923
|
+
});
|
|
924
|
+
|
|
678
925
|
// ../service-capture/claude-sessions/collector.ts
|
|
679
926
|
var collector_exports = {};
|
|
680
927
|
__export(collector_exports, {
|
|
@@ -735,40 +982,11 @@ function extractGitInfo(projectDir, sessionTimestamp, sessionBranch) {
|
|
|
735
982
|
}
|
|
736
983
|
return result;
|
|
737
984
|
}
|
|
738
|
-
function extractSessionMeta(filePath) {
|
|
739
|
-
const result = {
|
|
740
|
-
cwd: null,
|
|
741
|
-
timestamp: null,
|
|
742
|
-
gitBranch: null
|
|
743
|
-
};
|
|
744
|
-
try {
|
|
745
|
-
const content = (0, import_fs.readFileSync)(filePath, "utf-8");
|
|
746
|
-
const lines = content.split("\n").filter((l) => l.trim()).slice(0, 50);
|
|
747
|
-
for (const line of lines) {
|
|
748
|
-
try {
|
|
749
|
-
const entry = JSON.parse(line);
|
|
750
|
-
if (!result.cwd && entry.cwd && typeof entry.cwd === "string") {
|
|
751
|
-
result.cwd = entry.cwd;
|
|
752
|
-
}
|
|
753
|
-
if (!result.timestamp && entry.timestamp && typeof entry.timestamp === "string") {
|
|
754
|
-
result.timestamp = entry.timestamp;
|
|
755
|
-
}
|
|
756
|
-
if (!result.gitBranch && entry.gitBranch && typeof entry.gitBranch === "string") {
|
|
757
|
-
result.gitBranch = entry.gitBranch;
|
|
758
|
-
}
|
|
759
|
-
if (result.cwd && result.timestamp && result.gitBranch) break;
|
|
760
|
-
} catch {
|
|
761
|
-
}
|
|
762
|
-
}
|
|
763
|
-
} catch {
|
|
764
|
-
}
|
|
765
|
-
return result;
|
|
766
|
-
}
|
|
767
985
|
function resolveToken() {
|
|
768
986
|
if (process.env.HAANSI_TOKEN) return process.env.HAANSI_TOKEN;
|
|
769
|
-
if ((0,
|
|
987
|
+
if ((0, import_fs3.existsSync)(CREDENTIALS_FILE3)) {
|
|
770
988
|
try {
|
|
771
|
-
const creds = JSON.parse((0,
|
|
989
|
+
const creds = JSON.parse((0, import_fs3.readFileSync)(CREDENTIALS_FILE3, "utf-8"));
|
|
772
990
|
if (creds.token) return creds.token;
|
|
773
991
|
} catch {
|
|
774
992
|
logger.warn("Could not parse credentials file", {
|
|
@@ -778,41 +996,32 @@ function resolveToken() {
|
|
|
778
996
|
}
|
|
779
997
|
return null;
|
|
780
998
|
}
|
|
781
|
-
function
|
|
782
|
-
if (
|
|
999
|
+
function resolveAgentIds(agents) {
|
|
1000
|
+
if (agents && agents.length > 0) return agents;
|
|
1001
|
+
const installed = detectInstalled().map((a) => a.id);
|
|
1002
|
+
return installed.length > 0 ? installed : ["claude-code"];
|
|
1003
|
+
}
|
|
1004
|
+
function discoverSessions(agentIds) {
|
|
783
1005
|
const sessions = [];
|
|
784
|
-
|
|
1006
|
+
for (const id of agentIds) {
|
|
1007
|
+
const agent = getAgent(id);
|
|
1008
|
+
let discovered = [];
|
|
785
1009
|
try {
|
|
786
|
-
|
|
787
|
-
} catch {
|
|
788
|
-
|
|
1010
|
+
discovered = agent.discoverSessions();
|
|
1011
|
+
} catch (err) {
|
|
1012
|
+
logger.warn(`Discovery failed for ${agent.displayName}`, {
|
|
1013
|
+
err: err?.message
|
|
1014
|
+
});
|
|
1015
|
+
continue;
|
|
789
1016
|
}
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
const files = (0, import_fs.readdirSync)(dir).filter((f) => f.endsWith(".jsonl"));
|
|
793
|
-
for (const file2 of files) {
|
|
794
|
-
const filePath = (0, import_path.join)(dir, file2);
|
|
795
|
-
const sessionId = (0, import_path.basename)(file2, ".jsonl");
|
|
796
|
-
try {
|
|
797
|
-
const stat = (0, import_fs.statSync)(filePath);
|
|
798
|
-
const content = (0, import_fs.readFileSync)(filePath, "utf-8");
|
|
799
|
-
const lineCount = content.split("\n").filter((l) => l.trim()).length;
|
|
800
|
-
if (lineCount >= MIN_LINES) {
|
|
801
|
-
sessions.push({
|
|
802
|
-
sessionId,
|
|
803
|
-
filePath,
|
|
804
|
-
lineCount,
|
|
805
|
-
sizeBytes: stat.size
|
|
806
|
-
});
|
|
807
|
-
}
|
|
808
|
-
} catch {
|
|
809
|
-
}
|
|
1017
|
+
for (const s of discovered) {
|
|
1018
|
+
if (s.lineCount >= MIN_LINES) sessions.push({ ...s, agentId: id });
|
|
810
1019
|
}
|
|
811
1020
|
}
|
|
812
1021
|
return sessions;
|
|
813
1022
|
}
|
|
814
|
-
async function apiGet(path,
|
|
815
|
-
const response = await fetch(`${
|
|
1023
|
+
async function apiGet(path, apiUrl2, token) {
|
|
1024
|
+
const response = await fetch(`${apiUrl2}/api/v1${path}`, {
|
|
816
1025
|
headers: { Authorization: `Bearer ${token}` }
|
|
817
1026
|
});
|
|
818
1027
|
if (!response.ok) {
|
|
@@ -821,11 +1030,11 @@ async function apiGet(path, apiUrl, token) {
|
|
|
821
1030
|
}
|
|
822
1031
|
return response.json();
|
|
823
1032
|
}
|
|
824
|
-
async function getUploadedSessions(
|
|
1033
|
+
async function getUploadedSessions(apiUrl2, token) {
|
|
825
1034
|
try {
|
|
826
1035
|
const data = await apiGet(
|
|
827
1036
|
"/capture/sessions/uploaded",
|
|
828
|
-
|
|
1037
|
+
apiUrl2,
|
|
829
1038
|
token
|
|
830
1039
|
);
|
|
831
1040
|
const map2 = /* @__PURE__ */ new Map();
|
|
@@ -841,18 +1050,19 @@ async function getUploadedSessions(apiUrl, token) {
|
|
|
841
1050
|
return /* @__PURE__ */ new Map();
|
|
842
1051
|
}
|
|
843
1052
|
}
|
|
844
|
-
async function uploadSession(sessionId, content,
|
|
1053
|
+
async function uploadSession(sessionId, content, apiUrl2, token, agentSource, gitInfo) {
|
|
845
1054
|
const body = (0, import_zlib.gzipSync)(Buffer.from(content, "utf-8"));
|
|
846
1055
|
const headers = {
|
|
847
1056
|
Authorization: `Bearer ${token}`,
|
|
848
1057
|
"Content-Type": "application/x-ndjson",
|
|
849
1058
|
"Content-Encoding": "gzip",
|
|
850
|
-
"x-session-id": sessionId
|
|
1059
|
+
"x-session-id": sessionId,
|
|
1060
|
+
"x-haansi-agent-source": agentSource
|
|
851
1061
|
};
|
|
852
1062
|
if (gitInfo?.gitRemoteUrl) headers["x-git-remote-url"] = gitInfo.gitRemoteUrl;
|
|
853
1063
|
if (gitInfo?.gitCommit) headers["x-git-commit"] = gitInfo.gitCommit;
|
|
854
1064
|
if (gitInfo?.gitBranch) headers["x-git-branch"] = gitInfo.gitBranch;
|
|
855
|
-
const response = await fetch(`${
|
|
1065
|
+
const response = await fetch(`${apiUrl2}/api/v1/capture/sessions/raw`, {
|
|
856
1066
|
method: "POST",
|
|
857
1067
|
headers,
|
|
858
1068
|
body: new Uint8Array(body)
|
|
@@ -865,22 +1075,25 @@ async function uploadSession(sessionId, content, apiUrl, token, gitInfo) {
|
|
|
865
1075
|
}
|
|
866
1076
|
}
|
|
867
1077
|
async function collect(options) {
|
|
868
|
-
const
|
|
1078
|
+
const apiUrl2 = process.env.HAANSI_API_URL ?? DEFAULT_API_URL3;
|
|
869
1079
|
const token = resolveToken();
|
|
870
1080
|
if (!token && !options.dryRun) {
|
|
871
1081
|
throw new Error(
|
|
872
1082
|
"HAANSI_TOKEN is required. Set it as env var or in ~/.haansi/credentials.json"
|
|
873
1083
|
);
|
|
874
1084
|
}
|
|
875
|
-
const
|
|
876
|
-
|
|
1085
|
+
const agentIds = resolveAgentIds(options.agents);
|
|
1086
|
+
const localSessions = discoverSessions(agentIds);
|
|
1087
|
+
logger.info(`Found ${localSessions.length} session files on disk`, {
|
|
1088
|
+
agents: agentIds.join(",")
|
|
1089
|
+
});
|
|
877
1090
|
if (localSessions.length === 0) {
|
|
878
1091
|
return { uploaded: 0, skipped: 0, errors: 0 };
|
|
879
1092
|
}
|
|
880
1093
|
let uploaded = 0;
|
|
881
1094
|
let skipped = 0;
|
|
882
1095
|
let errors = 0;
|
|
883
|
-
const remoteMap = options.forceAll ? /* @__PURE__ */ new Map() : await getUploadedSessions(
|
|
1096
|
+
const remoteMap = options.forceAll ? /* @__PURE__ */ new Map() : await getUploadedSessions(apiUrl2, token);
|
|
884
1097
|
const toUpload = [];
|
|
885
1098
|
for (const session of localSessions) {
|
|
886
1099
|
const remote = remoteMap.get(session.sessionId);
|
|
@@ -898,22 +1111,22 @@ async function collect(options) {
|
|
|
898
1111
|
for (const session of batch) {
|
|
899
1112
|
const shortId = session.sessionId.slice(0, 8);
|
|
900
1113
|
try {
|
|
901
|
-
const rawContent = (0,
|
|
1114
|
+
const rawContent = (0, import_fs3.readFileSync)(session.filePath, "utf-8");
|
|
902
1115
|
const scrubbed = edgeScrub(rawContent);
|
|
903
|
-
const
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
sessionMeta.gitBranch ?? void 0
|
|
1116
|
+
const gitInfo = session.cwd ? extractGitInfo(
|
|
1117
|
+
session.cwd,
|
|
1118
|
+
session.timestamp ?? void 0,
|
|
1119
|
+
session.gitBranch ?? void 0
|
|
908
1120
|
) : {
|
|
909
1121
|
gitRemoteUrl: null,
|
|
910
1122
|
gitCommit: null,
|
|
911
|
-
gitBranch:
|
|
1123
|
+
gitBranch: session.gitBranch
|
|
912
1124
|
};
|
|
913
1125
|
if (options.dryRun) {
|
|
914
1126
|
logger.info(
|
|
915
|
-
`[dry-run] Would upload ${shortId} (${session.lineCount} lines)`,
|
|
1127
|
+
`[dry-run] Would upload ${shortId} (${session.agentId}, ${session.lineCount} lines)`,
|
|
916
1128
|
{
|
|
1129
|
+
agentSource: session.agentId,
|
|
917
1130
|
gitRemoteUrl: gitInfo.gitRemoteUrl,
|
|
918
1131
|
gitCommit: gitInfo.gitCommit?.slice(0, 8)
|
|
919
1132
|
}
|
|
@@ -921,12 +1134,23 @@ async function collect(options) {
|
|
|
921
1134
|
uploaded++;
|
|
922
1135
|
continue;
|
|
923
1136
|
}
|
|
924
|
-
await uploadSession(
|
|
1137
|
+
await uploadSession(
|
|
1138
|
+
session.sessionId,
|
|
1139
|
+
scrubbed,
|
|
1140
|
+
apiUrl2,
|
|
1141
|
+
token,
|
|
1142
|
+
session.agentId,
|
|
1143
|
+
gitInfo
|
|
1144
|
+
);
|
|
925
1145
|
uploaded++;
|
|
926
|
-
logger.info(
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
1146
|
+
logger.info(
|
|
1147
|
+
`Uploaded ${shortId} (${session.agentId}, ${session.lineCount} lines)`,
|
|
1148
|
+
{
|
|
1149
|
+
agentSource: session.agentId,
|
|
1150
|
+
gitRemoteUrl: gitInfo.gitRemoteUrl,
|
|
1151
|
+
gitCommit: gitInfo.gitCommit?.slice(0, 8)
|
|
1152
|
+
}
|
|
1153
|
+
);
|
|
930
1154
|
} catch (err) {
|
|
931
1155
|
errors++;
|
|
932
1156
|
logger.error(`Failed to upload ${shortId}`, { err: err.message });
|
|
@@ -947,22 +1171,22 @@ async function main() {
|
|
|
947
1171
|
});
|
|
948
1172
|
if (errors > 0) process.exit(1);
|
|
949
1173
|
}
|
|
950
|
-
var import_dotenv,
|
|
1174
|
+
var import_dotenv, import_path3, import_fs3, import_os3, import_zlib, import_child_process, logger, DEFAULT_API_URL3, CREDENTIALS_FILE3, MIN_LINES, EDGE_SCRUB_PATTERNS;
|
|
951
1175
|
var init_collector = __esm({
|
|
952
1176
|
"../service-capture/claude-sessions/collector.ts"() {
|
|
953
1177
|
"use strict";
|
|
954
1178
|
import_dotenv = __toESM(require_main());
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
1179
|
+
import_path3 = require("path");
|
|
1180
|
+
import_fs3 = require("fs");
|
|
1181
|
+
import_os3 = require("os");
|
|
958
1182
|
import_zlib = require("zlib");
|
|
959
1183
|
import_child_process = require("child_process");
|
|
960
1184
|
init_logger();
|
|
961
|
-
(
|
|
962
|
-
|
|
1185
|
+
init_agents();
|
|
1186
|
+
(0, import_dotenv.config)({ path: (0, import_path3.resolve)(__dirname, "../../../.env") });
|
|
1187
|
+
logger = createLogger("session-collector");
|
|
963
1188
|
DEFAULT_API_URL3 = "https://api.haansi.co";
|
|
964
|
-
CREDENTIALS_FILE3 = (0,
|
|
965
|
-
CLAUDE_PROJECTS_DIR = (0, import_path.join)((0, import_os.homedir)(), ".claude", "projects");
|
|
1189
|
+
CREDENTIALS_FILE3 = (0, import_path3.join)((0, import_os3.homedir)(), ".haansi", "credentials.json");
|
|
966
1190
|
MIN_LINES = 4;
|
|
967
1191
|
EDGE_SCRUB_PATTERNS = [
|
|
968
1192
|
{
|
|
@@ -1012,6 +1236,151 @@ var init_collector = __esm({
|
|
|
1012
1236
|
}
|
|
1013
1237
|
});
|
|
1014
1238
|
|
|
1239
|
+
// src/lib/paths.ts
|
|
1240
|
+
function apiUrl() {
|
|
1241
|
+
return process.env.HAANSI_API_URL ?? DEFAULT_API_URL4;
|
|
1242
|
+
}
|
|
1243
|
+
function resolveToken2() {
|
|
1244
|
+
if (process.env.HAANSI_TOKEN) return process.env.HAANSI_TOKEN;
|
|
1245
|
+
if ((0, import_node_fs3.existsSync)(CREDENTIALS_FILE4)) {
|
|
1246
|
+
try {
|
|
1247
|
+
const creds = JSON.parse((0, import_node_fs3.readFileSync)(CREDENTIALS_FILE4, "utf-8"));
|
|
1248
|
+
if (typeof creds.token === "string" && creds.token) return creds.token;
|
|
1249
|
+
} catch {
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
return null;
|
|
1253
|
+
}
|
|
1254
|
+
function resolveHaansiBin() {
|
|
1255
|
+
try {
|
|
1256
|
+
const binPath = (0, import_node_child_process2.execSync)("which haansi", { encoding: "utf-8" }).trim();
|
|
1257
|
+
if (binPath) return binPath;
|
|
1258
|
+
} catch {
|
|
1259
|
+
}
|
|
1260
|
+
return "haansi";
|
|
1261
|
+
}
|
|
1262
|
+
var import_node_fs3, import_node_path3, import_node_os3, import_node_child_process2, DEFAULT_API_URL4, HAANSI_DIR3, CREDENTIALS_FILE4, CONFIG_FILE;
|
|
1263
|
+
var init_paths = __esm({
|
|
1264
|
+
"src/lib/paths.ts"() {
|
|
1265
|
+
"use strict";
|
|
1266
|
+
import_node_fs3 = require("node:fs");
|
|
1267
|
+
import_node_path3 = require("node:path");
|
|
1268
|
+
import_node_os3 = require("node:os");
|
|
1269
|
+
import_node_child_process2 = require("node:child_process");
|
|
1270
|
+
DEFAULT_API_URL4 = "https://api.haansi.co";
|
|
1271
|
+
HAANSI_DIR3 = (0, import_node_path3.join)((0, import_node_os3.homedir)(), ".haansi");
|
|
1272
|
+
CREDENTIALS_FILE4 = (0, import_node_path3.join)(HAANSI_DIR3, "credentials.json");
|
|
1273
|
+
CONFIG_FILE = (0, import_node_path3.join)(HAANSI_DIR3, "config.json");
|
|
1274
|
+
}
|
|
1275
|
+
});
|
|
1276
|
+
|
|
1277
|
+
// src/lib/agent-selection.ts
|
|
1278
|
+
var agent_selection_exports = {};
|
|
1279
|
+
__export(agent_selection_exports, {
|
|
1280
|
+
parseAgentFlag: () => parseAgentFlag,
|
|
1281
|
+
promptForAgents: () => promptForAgents,
|
|
1282
|
+
readSavedAgents: () => readSavedAgents,
|
|
1283
|
+
resolveAgentSelection: () => resolveAgentSelection,
|
|
1284
|
+
saveAgents: () => saveAgents
|
|
1285
|
+
});
|
|
1286
|
+
function parseAgentFlag(value) {
|
|
1287
|
+
if (!value) return null;
|
|
1288
|
+
const normalized = value.trim().toLowerCase();
|
|
1289
|
+
if (normalized === "both" || normalized === "all") return [...VALID];
|
|
1290
|
+
const out = [];
|
|
1291
|
+
for (const part of normalized.split(",").map((s) => s.trim())) {
|
|
1292
|
+
if (part === "claude" || part === "claude-code") {
|
|
1293
|
+
if (!out.includes("claude-code")) out.push("claude-code");
|
|
1294
|
+
} else if (part === "codex") {
|
|
1295
|
+
if (!out.includes("codex")) out.push("codex");
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
return out.length > 0 ? out : null;
|
|
1299
|
+
}
|
|
1300
|
+
function readSavedAgents() {
|
|
1301
|
+
if (!(0, import_node_fs4.existsSync)(CONFIG_FILE)) return null;
|
|
1302
|
+
try {
|
|
1303
|
+
const cfg = JSON.parse((0, import_node_fs4.readFileSync)(CONFIG_FILE, "utf-8"));
|
|
1304
|
+
if (Array.isArray(cfg.agents)) {
|
|
1305
|
+
const agents = cfg.agents.filter(
|
|
1306
|
+
(a) => VALID.includes(a)
|
|
1307
|
+
);
|
|
1308
|
+
return agents.length > 0 ? agents : null;
|
|
1309
|
+
}
|
|
1310
|
+
} catch {
|
|
1311
|
+
}
|
|
1312
|
+
return null;
|
|
1313
|
+
}
|
|
1314
|
+
function saveAgents(agents) {
|
|
1315
|
+
let cfg = {};
|
|
1316
|
+
if ((0, import_node_fs4.existsSync)(CONFIG_FILE)) {
|
|
1317
|
+
try {
|
|
1318
|
+
cfg = JSON.parse((0, import_node_fs4.readFileSync)(CONFIG_FILE, "utf-8"));
|
|
1319
|
+
} catch {
|
|
1320
|
+
cfg = {};
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
cfg.agents = agents;
|
|
1324
|
+
(0, import_node_fs4.mkdirSync)(HAANSI_DIR3, { recursive: true });
|
|
1325
|
+
(0, import_node_fs4.writeFileSync)(CONFIG_FILE, JSON.stringify(cfg, null, 2) + "\n", {
|
|
1326
|
+
encoding: "utf-8",
|
|
1327
|
+
mode: 384
|
|
1328
|
+
});
|
|
1329
|
+
}
|
|
1330
|
+
function resolveAgentSelection(flagValue) {
|
|
1331
|
+
const fromFlag = parseAgentFlag(flagValue);
|
|
1332
|
+
if (fromFlag) return { agents: fromFlag, source: "flag" };
|
|
1333
|
+
const saved = readSavedAgents();
|
|
1334
|
+
if (saved) return { agents: saved, source: "config" };
|
|
1335
|
+
const detected = detectInstalled().map((a) => a.id);
|
|
1336
|
+
if (detected.length > 0) return { agents: detected, source: "detected" };
|
|
1337
|
+
return { agents: ["claude-code"], source: "default" };
|
|
1338
|
+
}
|
|
1339
|
+
async function promptForAgents() {
|
|
1340
|
+
const installed = new Set(detectInstalled().map((a) => a.id));
|
|
1341
|
+
const agents = getAgents();
|
|
1342
|
+
console.log("\nWhich coding agents should Haansi connect?\n");
|
|
1343
|
+
agents.forEach((a, i) => {
|
|
1344
|
+
const mark = installed.has(a.id) ? "installed" : "not detected";
|
|
1345
|
+
console.log(` ${i + 1}) ${a.displayName} (${mark})`);
|
|
1346
|
+
});
|
|
1347
|
+
const rl = readline2.createInterface({
|
|
1348
|
+
input: process.stdin,
|
|
1349
|
+
output: process.stdout
|
|
1350
|
+
});
|
|
1351
|
+
const answer = await new Promise((resolve4) => {
|
|
1352
|
+
rl.question(
|
|
1353
|
+
"\nEnter numbers (comma-separated), or press Enter for all installed: ",
|
|
1354
|
+
(a) => {
|
|
1355
|
+
rl.close();
|
|
1356
|
+
resolve4(a.trim());
|
|
1357
|
+
}
|
|
1358
|
+
);
|
|
1359
|
+
});
|
|
1360
|
+
if (!answer) {
|
|
1361
|
+
const detected = agents.filter((a) => installed.has(a.id)).map((a) => a.id);
|
|
1362
|
+
return detected.length > 0 ? detected : [...VALID];
|
|
1363
|
+
}
|
|
1364
|
+
const picked = [];
|
|
1365
|
+
for (const token of answer.split(",").map((s) => s.trim())) {
|
|
1366
|
+
const idx = parseInt(token, 10) - 1;
|
|
1367
|
+
const agent = agents[idx];
|
|
1368
|
+
if (agent && !picked.includes(agent.id)) picked.push(agent.id);
|
|
1369
|
+
}
|
|
1370
|
+
return picked.length > 0 ? picked : [...VALID];
|
|
1371
|
+
}
|
|
1372
|
+
var import_node_fs4, readline2, VALID;
|
|
1373
|
+
var init_agent_selection = __esm({
|
|
1374
|
+
"src/lib/agent-selection.ts"() {
|
|
1375
|
+
"use strict";
|
|
1376
|
+
import_node_fs4 = require("node:fs");
|
|
1377
|
+
readline2 = __toESM(require("node:readline"));
|
|
1378
|
+
init_agents();
|
|
1379
|
+
init_paths();
|
|
1380
|
+
VALID = ["claude-code", "codex"];
|
|
1381
|
+
}
|
|
1382
|
+
});
|
|
1383
|
+
|
|
1015
1384
|
// ../../node_modules/node-cron/src/task.js
|
|
1016
1385
|
var require_task = __commonJS({
|
|
1017
1386
|
"../../node_modules/node-cron/src/task.js"(exports2, module2) {
|
|
@@ -1924,23 +2293,30 @@ var require_node_cron = __commonJS({
|
|
|
1924
2293
|
|
|
1925
2294
|
// ../service-capture/claude-sessions/collector-daemon.ts
|
|
1926
2295
|
var collector_daemon_exports = {};
|
|
2296
|
+
function resolveAgentsEnv() {
|
|
2297
|
+
const raw = process.env.HAANSI_AGENTS;
|
|
2298
|
+
if (!raw) return void 0;
|
|
2299
|
+
const valid = ["claude-code", "codex"];
|
|
2300
|
+
const parsed = raw.split(",").map((s) => s.trim().toLowerCase()).filter((s) => valid.includes(s));
|
|
2301
|
+
return parsed.length > 0 ? parsed : void 0;
|
|
2302
|
+
}
|
|
1927
2303
|
function getOnDiskVersion() {
|
|
1928
2304
|
try {
|
|
1929
|
-
const realEntry = (0,
|
|
1930
|
-
const pkgPath = (0,
|
|
1931
|
-
if (!(0,
|
|
1932
|
-
const pkg = JSON.parse((0,
|
|
2305
|
+
const realEntry = (0, import_fs4.realpathSync)(process.argv[1]);
|
|
2306
|
+
const pkgPath = (0, import_path4.resolve)((0, import_path4.dirname)(realEntry), "..", "package.json");
|
|
2307
|
+
if (!(0, import_fs4.existsSync)(pkgPath)) return null;
|
|
2308
|
+
const pkg = JSON.parse((0, import_fs4.readFileSync)(pkgPath, "utf-8"));
|
|
1933
2309
|
return pkg.version ?? null;
|
|
1934
2310
|
} catch {
|
|
1935
2311
|
return null;
|
|
1936
2312
|
}
|
|
1937
2313
|
}
|
|
1938
2314
|
async function run() {
|
|
1939
|
-
const
|
|
1940
|
-
logger2.info("Collect run starting", {
|
|
2315
|
+
const agents = resolveAgentsEnv();
|
|
2316
|
+
logger2.info("Collect run starting", { agents: agents?.join(",") ?? "all" });
|
|
1941
2317
|
const start = Date.now();
|
|
1942
2318
|
try {
|
|
1943
|
-
const { uploaded, skipped, errors } = await collect({
|
|
2319
|
+
const { uploaded, skipped, errors } = await collect({ agents });
|
|
1944
2320
|
const elapsed = ((Date.now() - start) / 1e3).toFixed(1);
|
|
1945
2321
|
logger2.info(`Collect run complete in ${elapsed}s`, {
|
|
1946
2322
|
uploaded,
|
|
@@ -1977,20 +2353,20 @@ async function main2() {
|
|
|
1977
2353
|
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
1978
2354
|
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
1979
2355
|
}
|
|
1980
|
-
var import_dotenv2,
|
|
2356
|
+
var import_dotenv2, import_fs4, import_path4, import_node_cron, logger2, IN_MEMORY_VERSION, SCHEDULE;
|
|
1981
2357
|
var init_collector_daemon = __esm({
|
|
1982
2358
|
"../service-capture/claude-sessions/collector-daemon.ts"() {
|
|
1983
2359
|
"use strict";
|
|
1984
2360
|
import_dotenv2 = __toESM(require_main());
|
|
1985
|
-
|
|
1986
|
-
|
|
2361
|
+
import_fs4 = require("fs");
|
|
2362
|
+
import_path4 = require("path");
|
|
1987
2363
|
import_node_cron = __toESM(require_node_cron());
|
|
1988
2364
|
init_collector();
|
|
1989
2365
|
init_logger();
|
|
1990
|
-
(0, import_dotenv2.config)({ path: (0,
|
|
2366
|
+
(0, import_dotenv2.config)({ path: (0, import_path4.resolve)(__dirname, "../../../.env") });
|
|
1991
2367
|
logger2 = createLogger("collector-daemon");
|
|
1992
2368
|
IN_MEMORY_VERSION = require_package().version;
|
|
1993
|
-
SCHEDULE = process.env.CLAUDE_COLLECT_SCHEDULE ?? "*/30 * * * *";
|
|
2369
|
+
SCHEDULE = process.env.HAANSI_COLLECT_SCHEDULE ?? process.env.CLAUDE_COLLECT_SCHEDULE ?? "*/30 * * * *";
|
|
1994
2370
|
main2().catch((err) => {
|
|
1995
2371
|
logger2.error("Daemon failed to start", err);
|
|
1996
2372
|
process.exit(1);
|
|
@@ -2907,7 +3283,7 @@ function createZodEnum(values, params) {
|
|
|
2907
3283
|
});
|
|
2908
3284
|
}
|
|
2909
3285
|
var ParseInputLazyPath, handleResult, ZodType, cuidRegex, cuid2Regex, ulidRegex, uuidRegex, nanoidRegex, jwtRegex, durationRegex, emailRegex, _emojiRegex, emojiRegex, ipv4Regex, ipv4CidrRegex, ipv6Regex, ipv6CidrRegex, base64Regex, base64urlRegex, dateRegexSource, dateRegex, ZodString, ZodNumber, ZodBigInt, ZodBoolean, ZodDate, ZodSymbol, ZodUndefined, ZodNull, ZodAny, ZodUnknown, ZodNever, ZodVoid, ZodArray, ZodObject, ZodUnion, getDiscriminator, ZodDiscriminatedUnion, ZodIntersection, ZodTuple, ZodRecord, ZodMap, ZodSet, ZodFunction, ZodLazy, ZodLiteral, ZodEnum, ZodNativeEnum, ZodPromise, ZodEffects, ZodOptional, ZodNullable, ZodDefault, ZodCatch, ZodNaN, BRAND, ZodBranded, ZodPipeline, ZodReadonly, late, ZodFirstPartyTypeKind, stringType, numberType, nanType, bigIntType, booleanType, dateType, symbolType, undefinedType, nullType, anyType, unknownType, neverType, voidType, arrayType, objectType, strictObjectType, unionType, discriminatedUnionType, intersectionType, tupleType, recordType, mapType, setType, functionType, lazyType, literalType, enumType, nativeEnumType, promiseType, effectsType, optionalType, nullableType, preprocessType, pipelineType;
|
|
2910
|
-
var
|
|
3286
|
+
var init_types2 = __esm({
|
|
2911
3287
|
"../../node_modules/zod/v3/types.js"() {
|
|
2912
3288
|
init_ZodError();
|
|
2913
3289
|
init_errors();
|
|
@@ -6160,7 +6536,7 @@ var init_external = __esm({
|
|
|
6160
6536
|
init_parseUtil();
|
|
6161
6537
|
init_typeAliases();
|
|
6162
6538
|
init_util();
|
|
6163
|
-
|
|
6539
|
+
init_types2();
|
|
6164
6540
|
init_ZodError();
|
|
6165
6541
|
}
|
|
6166
6542
|
});
|
|
@@ -13942,7 +14318,7 @@ function assertCompleteRequestResourceTemplate(request) {
|
|
|
13942
14318
|
void request;
|
|
13943
14319
|
}
|
|
13944
14320
|
var LATEST_PROTOCOL_VERSION, DEFAULT_NEGOTIATED_PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS, RELATED_TASK_META_KEY, JSONRPC_VERSION, AssertObjectSchema, ProgressTokenSchema, CursorSchema, TaskCreationParamsSchema, TaskMetadataSchema, RelatedTaskMetadataSchema, RequestMetaSchema, BaseRequestParamsSchema, TaskAugmentedRequestParamsSchema, isTaskAugmentedRequestParams, RequestSchema, NotificationsParamsSchema, NotificationSchema, ResultSchema, RequestIdSchema, JSONRPCRequestSchema, isJSONRPCRequest, JSONRPCNotificationSchema, isJSONRPCNotification, JSONRPCResultResponseSchema, isJSONRPCResultResponse, ErrorCode, JSONRPCErrorResponseSchema, isJSONRPCErrorResponse, JSONRPCMessageSchema, JSONRPCResponseSchema, EmptyResultSchema, CancelledNotificationParamsSchema, CancelledNotificationSchema, IconSchema, IconsSchema, BaseMetadataSchema, ImplementationSchema, FormElicitationCapabilitySchema, ElicitationCapabilitySchema, ClientTasksCapabilitySchema, ServerTasksCapabilitySchema, ClientCapabilitiesSchema, InitializeRequestParamsSchema, InitializeRequestSchema, isInitializeRequest, ServerCapabilitiesSchema, InitializeResultSchema, InitializedNotificationSchema, PingRequestSchema, ProgressSchema, ProgressNotificationParamsSchema, ProgressNotificationSchema, PaginatedRequestParamsSchema, PaginatedRequestSchema, PaginatedResultSchema, TaskStatusSchema, TaskSchema, CreateTaskResultSchema, TaskStatusNotificationParamsSchema, TaskStatusNotificationSchema, GetTaskRequestSchema, GetTaskResultSchema, GetTaskPayloadRequestSchema, GetTaskPayloadResultSchema, ListTasksRequestSchema, ListTasksResultSchema, CancelTaskRequestSchema, CancelTaskResultSchema, ResourceContentsSchema, TextResourceContentsSchema, Base64Schema, BlobResourceContentsSchema, RoleSchema, AnnotationsSchema, ResourceSchema, ResourceTemplateSchema, ListResourcesRequestSchema, ListResourcesResultSchema, ListResourceTemplatesRequestSchema, ListResourceTemplatesResultSchema, ResourceRequestParamsSchema, ReadResourceRequestParamsSchema, ReadResourceRequestSchema, ReadResourceResultSchema, ResourceListChangedNotificationSchema, SubscribeRequestParamsSchema, SubscribeRequestSchema, UnsubscribeRequestParamsSchema, UnsubscribeRequestSchema, ResourceUpdatedNotificationParamsSchema, ResourceUpdatedNotificationSchema, PromptArgumentSchema, PromptSchema, ListPromptsRequestSchema, ListPromptsResultSchema, GetPromptRequestParamsSchema, GetPromptRequestSchema, TextContentSchema, ImageContentSchema, AudioContentSchema, ToolUseContentSchema, EmbeddedResourceSchema, ResourceLinkSchema, ContentBlockSchema, PromptMessageSchema, GetPromptResultSchema, PromptListChangedNotificationSchema, ToolAnnotationsSchema, ToolExecutionSchema, ToolSchema, ListToolsRequestSchema, ListToolsResultSchema, CallToolResultSchema, CompatibilityCallToolResultSchema, CallToolRequestParamsSchema, CallToolRequestSchema, ToolListChangedNotificationSchema, ListChangedOptionsBaseSchema, LoggingLevelSchema, SetLevelRequestParamsSchema, SetLevelRequestSchema, LoggingMessageNotificationParamsSchema, LoggingMessageNotificationSchema, ModelHintSchema, ModelPreferencesSchema, ToolChoiceSchema, ToolResultContentSchema, SamplingContentSchema, SamplingMessageContentBlockSchema, SamplingMessageSchema, CreateMessageRequestParamsSchema, CreateMessageRequestSchema, CreateMessageResultSchema, CreateMessageResultWithToolsSchema, BooleanSchemaSchema, StringSchemaSchema, NumberSchemaSchema, UntitledSingleSelectEnumSchemaSchema, TitledSingleSelectEnumSchemaSchema, LegacyTitledEnumSchemaSchema, SingleSelectEnumSchemaSchema, UntitledMultiSelectEnumSchemaSchema, TitledMultiSelectEnumSchemaSchema, MultiSelectEnumSchemaSchema, EnumSchemaSchema, PrimitiveSchemaDefinitionSchema, ElicitRequestFormParamsSchema, ElicitRequestURLParamsSchema, ElicitRequestParamsSchema, ElicitRequestSchema, ElicitationCompleteNotificationParamsSchema, ElicitationCompleteNotificationSchema, ElicitResultSchema, ResourceTemplateReferenceSchema, PromptReferenceSchema, CompleteRequestParamsSchema, CompleteRequestSchema, CompleteResultSchema, RootSchema, ListRootsRequestSchema, ListRootsResultSchema, RootsListChangedNotificationSchema, ClientRequestSchema, ClientNotificationSchema, ClientResultSchema, ServerRequestSchema, ServerNotificationSchema, ServerResultSchema, McpError, UrlElicitationRequiredError;
|
|
13945
|
-
var
|
|
14321
|
+
var init_types3 = __esm({
|
|
13946
14322
|
"../service-capture/node_modules/@modelcontextprotocol/sdk/dist/esm/types.js"() {
|
|
13947
14323
|
init_v42();
|
|
13948
14324
|
LATEST_PROTOCOL_VERSION = "2025-11-25";
|
|
@@ -17108,7 +17484,7 @@ var DEFAULT_REQUEST_TIMEOUT_MSEC, Protocol;
|
|
|
17108
17484
|
var init_protocol = __esm({
|
|
17109
17485
|
"../service-capture/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/protocol.js"() {
|
|
17110
17486
|
init_zod_compat();
|
|
17111
|
-
|
|
17487
|
+
init_types3();
|
|
17112
17488
|
init_interfaces();
|
|
17113
17489
|
init_zod_json_schema_compat();
|
|
17114
17490
|
DEFAULT_REQUEST_TIMEOUT_MSEC = 6e4;
|
|
@@ -30690,7 +31066,7 @@ var Server;
|
|
|
30690
31066
|
var init_server2 = __esm({
|
|
30691
31067
|
"../service-capture/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js"() {
|
|
30692
31068
|
init_protocol();
|
|
30693
|
-
|
|
31069
|
+
init_types3();
|
|
30694
31070
|
init_ajv_provider();
|
|
30695
31071
|
init_zod_compat();
|
|
30696
31072
|
init_server();
|
|
@@ -31260,7 +31636,7 @@ var init_mcp = __esm({
|
|
|
31260
31636
|
init_server2();
|
|
31261
31637
|
init_zod_compat();
|
|
31262
31638
|
init_zod_json_schema_compat();
|
|
31263
|
-
|
|
31639
|
+
init_types3();
|
|
31264
31640
|
init_completable();
|
|
31265
31641
|
init_uriTemplate();
|
|
31266
31642
|
init_toolNameValidation();
|
|
@@ -32001,7 +32377,7 @@ function serializeMessage(message) {
|
|
|
32001
32377
|
var ReadBuffer;
|
|
32002
32378
|
var init_stdio = __esm({
|
|
32003
32379
|
"../service-capture/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js"() {
|
|
32004
|
-
|
|
32380
|
+
init_types3();
|
|
32005
32381
|
ReadBuffer = class {
|
|
32006
32382
|
append(chunk) {
|
|
32007
32383
|
this._buffer = this._buffer ? Buffer.concat([this._buffer, chunk]) : chunk;
|
|
@@ -50810,9 +51186,9 @@ var require_view = __commonJS({
|
|
|
50810
51186
|
var path = require("node:path");
|
|
50811
51187
|
var fs = require("node:fs");
|
|
50812
51188
|
var dirname2 = path.dirname;
|
|
50813
|
-
var
|
|
51189
|
+
var basename3 = path.basename;
|
|
50814
51190
|
var extname = path.extname;
|
|
50815
|
-
var
|
|
51191
|
+
var join12 = path.join;
|
|
50816
51192
|
var resolve4 = path.resolve;
|
|
50817
51193
|
module2.exports = View;
|
|
50818
51194
|
function View(name, options) {
|
|
@@ -50849,7 +51225,7 @@ var require_view = __commonJS({
|
|
|
50849
51225
|
var root = roots[i];
|
|
50850
51226
|
var loc = resolve4(root, name);
|
|
50851
51227
|
var dir = dirname2(loc);
|
|
50852
|
-
var file2 =
|
|
51228
|
+
var file2 = basename3(loc);
|
|
50853
51229
|
path2 = this.resolve(dir, file2);
|
|
50854
51230
|
}
|
|
50855
51231
|
return path2;
|
|
@@ -50874,12 +51250,12 @@ var require_view = __commonJS({
|
|
|
50874
51250
|
};
|
|
50875
51251
|
View.prototype.resolve = function resolve5(dir, file2) {
|
|
50876
51252
|
var ext = this.ext;
|
|
50877
|
-
var path2 =
|
|
51253
|
+
var path2 = join12(dir, file2);
|
|
50878
51254
|
var stat = tryStat(path2);
|
|
50879
51255
|
if (stat && stat.isFile()) {
|
|
50880
51256
|
return path2;
|
|
50881
51257
|
}
|
|
50882
|
-
path2 =
|
|
51258
|
+
path2 = join12(dir, basename3(file2, ext), "index" + ext);
|
|
50883
51259
|
stat = tryStat(path2);
|
|
50884
51260
|
if (stat && stat.isFile()) {
|
|
50885
51261
|
return path2;
|
|
@@ -54163,7 +54539,7 @@ var require_content_disposition = __commonJS({
|
|
|
54163
54539
|
"use strict";
|
|
54164
54540
|
module2.exports = contentDisposition;
|
|
54165
54541
|
module2.exports.parse = parse4;
|
|
54166
|
-
var
|
|
54542
|
+
var basename3 = require("path").basename;
|
|
54167
54543
|
var ENCODE_URL_ATTR_CHAR_REGEXP = /[\x00-\x20"'()*,/:;<=>?@[\\\]{}\x7f]/g;
|
|
54168
54544
|
var HEX_ESCAPE_REGEXP = /%[0-9A-Fa-f]{2}/;
|
|
54169
54545
|
var HEX_ESCAPE_REPLACE_REGEXP = /%([0-9A-Fa-f]{2})/g;
|
|
@@ -54198,9 +54574,9 @@ var require_content_disposition = __commonJS({
|
|
|
54198
54574
|
if (typeof fallback === "string" && NON_LATIN1_REGEXP.test(fallback)) {
|
|
54199
54575
|
throw new TypeError("fallback must be ISO-8859-1 string");
|
|
54200
54576
|
}
|
|
54201
|
-
var name =
|
|
54577
|
+
var name = basename3(filename);
|
|
54202
54578
|
var isQuotedString = TEXT_REGEXP.test(name);
|
|
54203
|
-
var fallbackName = typeof fallback !== "string" ? fallback && getlatin1(name) :
|
|
54579
|
+
var fallbackName = typeof fallback !== "string" ? fallback && getlatin1(name) : basename3(fallback);
|
|
54204
54580
|
var hasFallback = typeof fallbackName === "string" && fallbackName !== name;
|
|
54205
54581
|
if (hasFallback || !isQuotedString || HEX_ESCAPE_REGEXP.test(name)) {
|
|
54206
54582
|
params["filename*"] = name;
|
|
@@ -54524,7 +54900,7 @@ var require_send = __commonJS({
|
|
|
54524
54900
|
var Stream = require("stream");
|
|
54525
54901
|
var util2 = require("util");
|
|
54526
54902
|
var extname = path.extname;
|
|
54527
|
-
var
|
|
54903
|
+
var join12 = path.join;
|
|
54528
54904
|
var normalize = path.normalize;
|
|
54529
54905
|
var resolve4 = path.resolve;
|
|
54530
54906
|
var sep = path.sep;
|
|
@@ -54696,7 +55072,7 @@ var require_send = __commonJS({
|
|
|
54696
55072
|
return res;
|
|
54697
55073
|
}
|
|
54698
55074
|
parts = path2.split(sep);
|
|
54699
|
-
path2 = normalize(
|
|
55075
|
+
path2 = normalize(join12(root, path2));
|
|
54700
55076
|
} else {
|
|
54701
55077
|
if (UP_PATH_REGEXP.test(path2)) {
|
|
54702
55078
|
debug('malicious path "%s"', path2);
|
|
@@ -54829,7 +55205,7 @@ var require_send = __commonJS({
|
|
|
54829
55205
|
if (err) return self.onStatError(err);
|
|
54830
55206
|
return self.error(404);
|
|
54831
55207
|
}
|
|
54832
|
-
var p =
|
|
55208
|
+
var p = join12(path2, self._index[i]);
|
|
54833
55209
|
debug('stat "%s"', p);
|
|
54834
55210
|
fs.stat(p, function(err2, stat) {
|
|
54835
55211
|
if (err2) return next(err2);
|
|
@@ -56223,7 +56599,7 @@ var init_dist = __esm({
|
|
|
56223
56599
|
var WebStandardStreamableHTTPServerTransport;
|
|
56224
56600
|
var init_webStandardStreamableHttp = __esm({
|
|
56225
56601
|
"../service-capture/node_modules/@modelcontextprotocol/sdk/dist/esm/server/webStandardStreamableHttp.js"() {
|
|
56226
|
-
|
|
56602
|
+
init_types3();
|
|
56227
56603
|
WebStandardStreamableHTTPServerTransport = class {
|
|
56228
56604
|
constructor(options = {}) {
|
|
56229
56605
|
this._started = false;
|
|
@@ -56924,11 +57300,11 @@ var init_streamableHttp = __esm({
|
|
|
56924
57300
|
|
|
56925
57301
|
// ../service-capture/claude-sessions/mcp-server.ts
|
|
56926
57302
|
var mcp_server_exports = {};
|
|
56927
|
-
function
|
|
57303
|
+
function resolveToken3() {
|
|
56928
57304
|
if (process.env.HAANSI_TOKEN) return process.env.HAANSI_TOKEN;
|
|
56929
|
-
if ((0,
|
|
57305
|
+
if ((0, import_fs5.existsSync)(CREDENTIALS_FILE5)) {
|
|
56930
57306
|
try {
|
|
56931
|
-
const creds = JSON.parse((0,
|
|
57307
|
+
const creds = JSON.parse((0, import_fs5.readFileSync)(CREDENTIALS_FILE5, "utf-8"));
|
|
56932
57308
|
if (creds.token) return creds.token;
|
|
56933
57309
|
} catch {
|
|
56934
57310
|
}
|
|
@@ -57013,25 +57389,25 @@ async function main3() {
|
|
|
57013
57389
|
}
|
|
57014
57390
|
warmupInBackground();
|
|
57015
57391
|
}
|
|
57016
|
-
var import_dotenv3,
|
|
57392
|
+
var import_dotenv3, import_path5, import_fs5, import_os4, DEFAULT_API_URL5, CREDENTIALS_FILE5, API_URL, TOKEN, contextSchema, isCollecting, lastCollectTime, COLLECT_COOLDOWN_MS, mcpServer, server;
|
|
57017
57393
|
var init_mcp_server2 = __esm({
|
|
57018
57394
|
"../service-capture/claude-sessions/mcp-server.ts"() {
|
|
57019
57395
|
"use strict";
|
|
57020
57396
|
import_dotenv3 = __toESM(require_main());
|
|
57021
|
-
|
|
57022
|
-
|
|
57023
|
-
|
|
57397
|
+
import_path5 = require("path");
|
|
57398
|
+
import_fs5 = require("fs");
|
|
57399
|
+
import_os4 = require("os");
|
|
57024
57400
|
init_collector();
|
|
57025
57401
|
init_http_timeout();
|
|
57026
57402
|
init_src();
|
|
57027
57403
|
init_mcp();
|
|
57028
57404
|
init_stdio2();
|
|
57029
|
-
|
|
57030
|
-
(0, import_dotenv3.config)({ path: (0,
|
|
57031
|
-
|
|
57032
|
-
|
|
57033
|
-
API_URL = process.env.HAANSI_API_URL ??
|
|
57034
|
-
TOKEN =
|
|
57405
|
+
init_types3();
|
|
57406
|
+
(0, import_dotenv3.config)({ path: (0, import_path5.resolve)(__dirname, "../../../.env") });
|
|
57407
|
+
DEFAULT_API_URL5 = "https://api.haansi.co";
|
|
57408
|
+
CREDENTIALS_FILE5 = (0, import_path5.join)((0, import_os4.homedir)(), ".haansi", "credentials.json");
|
|
57409
|
+
API_URL = process.env.HAANSI_API_URL ?? DEFAULT_API_URL5;
|
|
57410
|
+
TOKEN = resolveToken3();
|
|
57035
57411
|
if (!TOKEN) {
|
|
57036
57412
|
process.exit(1);
|
|
57037
57413
|
}
|
|
@@ -57323,30 +57699,59 @@ var init_mcp_server2 = __esm({
|
|
|
57323
57699
|
}
|
|
57324
57700
|
});
|
|
57325
57701
|
|
|
57702
|
+
// src/lib/codex-config.ts
|
|
57703
|
+
function tomlString(value) {
|
|
57704
|
+
const escaped = value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n");
|
|
57705
|
+
return `"${escaped}"`;
|
|
57706
|
+
}
|
|
57707
|
+
function tomlStringArray(values) {
|
|
57708
|
+
return `[${values.map(tomlString).join(", ")}]`;
|
|
57709
|
+
}
|
|
57710
|
+
function tomlInlineTable(entries) {
|
|
57711
|
+
const parts = Object.entries(entries).map(
|
|
57712
|
+
([k, v]) => `${k} = ${tomlString(v)}`
|
|
57713
|
+
);
|
|
57714
|
+
return `{ ${parts.join(", ")} }`;
|
|
57715
|
+
}
|
|
57716
|
+
function upsertTomlTable(content, tablePath, entries) {
|
|
57717
|
+
const bodyLines = Object.entries(entries).map(([k, v]) => `${k} = ${v}`);
|
|
57718
|
+
const block = [`[${tablePath}]`, ...bodyLines].join("\n");
|
|
57719
|
+
const lines = content.split("\n");
|
|
57720
|
+
const headerRe = new RegExp(
|
|
57721
|
+
`^\\s*\\[\\s*${tablePath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\s*\\]\\s*$`
|
|
57722
|
+
);
|
|
57723
|
+
const startIdx = lines.findIndex((l) => headerRe.test(l));
|
|
57724
|
+
if (startIdx === -1) {
|
|
57725
|
+
const trimmed = content.replace(/\s*$/, "");
|
|
57726
|
+
return trimmed.length > 0 ? `${trimmed}
|
|
57727
|
+
|
|
57728
|
+
${block}
|
|
57729
|
+
` : `${block}
|
|
57730
|
+
`;
|
|
57731
|
+
}
|
|
57732
|
+
let endIdx = lines.length;
|
|
57733
|
+
for (let i = startIdx + 1; i < lines.length; i++) {
|
|
57734
|
+
if (/^\s*\[/.test(lines[i])) {
|
|
57735
|
+
endIdx = i;
|
|
57736
|
+
break;
|
|
57737
|
+
}
|
|
57738
|
+
}
|
|
57739
|
+
const before = lines.slice(0, startIdx);
|
|
57740
|
+
const after = lines.slice(endIdx);
|
|
57741
|
+
const rebuilt = [...before, ...block.split("\n"), ...after].join("\n");
|
|
57742
|
+
return rebuilt.replace(/\n{3,}/g, "\n\n");
|
|
57743
|
+
}
|
|
57744
|
+
var init_codex_config = __esm({
|
|
57745
|
+
"src/lib/codex-config.ts"() {
|
|
57746
|
+
"use strict";
|
|
57747
|
+
}
|
|
57748
|
+
});
|
|
57749
|
+
|
|
57326
57750
|
// src/commands/setup-mcp.ts
|
|
57327
57751
|
var setup_mcp_exports = {};
|
|
57328
57752
|
__export(setup_mcp_exports, {
|
|
57329
57753
|
setupMcp: () => setupMcp
|
|
57330
57754
|
});
|
|
57331
|
-
function resolveHaansiBin() {
|
|
57332
|
-
try {
|
|
57333
|
-
const binPath = (0, import_node_child_process2.execSync)("which haansi", { encoding: "utf-8" }).trim();
|
|
57334
|
-
if (binPath) return binPath;
|
|
57335
|
-
} catch {
|
|
57336
|
-
}
|
|
57337
|
-
return "haansi";
|
|
57338
|
-
}
|
|
57339
|
-
function resolveToken3() {
|
|
57340
|
-
if (process.env.HAANSI_TOKEN) return process.env.HAANSI_TOKEN;
|
|
57341
|
-
if ((0, import_node_fs3.existsSync)(CREDENTIALS_FILE5)) {
|
|
57342
|
-
try {
|
|
57343
|
-
const creds = JSON.parse((0, import_node_fs3.readFileSync)(CREDENTIALS_FILE5, "utf-8"));
|
|
57344
|
-
if (typeof creds.token === "string" && creds.token) return creds.token;
|
|
57345
|
-
} catch {
|
|
57346
|
-
}
|
|
57347
|
-
}
|
|
57348
|
-
return null;
|
|
57349
|
-
}
|
|
57350
57755
|
function parseTarget(arg) {
|
|
57351
57756
|
if (!arg || arg === "all") return "all";
|
|
57352
57757
|
if (arg === "solutions" || arg === "exchange") return arg;
|
|
@@ -57354,12 +57759,14 @@ function parseTarget(arg) {
|
|
|
57354
57759
|
`Unknown target: ${arg}. Use one of: solutions, exchange, all (default).`
|
|
57355
57760
|
);
|
|
57356
57761
|
}
|
|
57357
|
-
|
|
57358
|
-
|
|
57762
|
+
function exchangeUrl() {
|
|
57763
|
+
return `${apiUrl().replace(/\/+$/, "")}/api/v1/access/exchange/mcp`;
|
|
57764
|
+
}
|
|
57765
|
+
function setupClaudeMcp(target) {
|
|
57359
57766
|
let config6 = {};
|
|
57360
|
-
if ((0,
|
|
57767
|
+
if ((0, import_node_fs5.existsSync)(CLAUDE_JSON)) {
|
|
57361
57768
|
try {
|
|
57362
|
-
config6 = JSON.parse((0,
|
|
57769
|
+
config6 = JSON.parse((0, import_node_fs5.readFileSync)(CLAUDE_JSON, "utf-8"));
|
|
57363
57770
|
} catch {
|
|
57364
57771
|
console.error(
|
|
57365
57772
|
`Warning: Could not parse ${CLAUDE_JSON} \u2014 will overwrite with new config.`
|
|
@@ -57378,42 +57785,100 @@ async function setupMcp(targetArg) {
|
|
|
57378
57785
|
installed.push(`haansi-solutions (stdio \u2192 ${haansiBin} mcp-server)`);
|
|
57379
57786
|
}
|
|
57380
57787
|
if (target === "all" || target === "exchange") {
|
|
57381
|
-
const token =
|
|
57788
|
+
const token = resolveToken2();
|
|
57382
57789
|
if (!token) {
|
|
57383
|
-
|
|
57384
|
-
|
|
57385
|
-
|
|
57386
|
-
process.exit(1);
|
|
57387
|
-
}
|
|
57388
|
-
warnings.push(msg);
|
|
57790
|
+
warnings.push(
|
|
57791
|
+
"haansi-exchange not registered: no token found. Run `haansi auth login` first, or set HAANSI_TOKEN."
|
|
57792
|
+
);
|
|
57389
57793
|
} else {
|
|
57390
|
-
const
|
|
57391
|
-
const exchangeUrl = `${apiUrl.replace(/\/+$/, "")}/api/v1/access/exchange/mcp`;
|
|
57794
|
+
const url2 = exchangeUrl();
|
|
57392
57795
|
config6.mcpServers["haansi-exchange"] = {
|
|
57393
57796
|
type: "http",
|
|
57394
|
-
url:
|
|
57797
|
+
url: url2,
|
|
57395
57798
|
headers: { Authorization: `Bearer ${token}` }
|
|
57396
57799
|
};
|
|
57397
|
-
installed.push(`haansi-exchange (http \u2192 ${
|
|
57800
|
+
installed.push(`haansi-exchange (http \u2192 ${url2})`);
|
|
57801
|
+
}
|
|
57802
|
+
}
|
|
57803
|
+
(0, import_node_fs5.writeFileSync)(CLAUDE_JSON, JSON.stringify(config6, null, 2) + "\n", "utf-8");
|
|
57804
|
+
console.log(`
|
|
57805
|
+
Claude Code \u2014 configured in ${CLAUDE_JSON}`);
|
|
57806
|
+
for (const entry of installed) console.log(` \u2022 ${entry}`);
|
|
57807
|
+
for (const w of warnings) console.log(` ! ${w}`);
|
|
57808
|
+
return { installed, warnings };
|
|
57809
|
+
}
|
|
57810
|
+
function setupCodexMcp(target) {
|
|
57811
|
+
let content = "";
|
|
57812
|
+
if ((0, import_node_fs5.existsSync)(CODEX_CONFIG)) {
|
|
57813
|
+
try {
|
|
57814
|
+
content = (0, import_node_fs5.readFileSync)(CODEX_CONFIG, "utf-8");
|
|
57815
|
+
} catch {
|
|
57816
|
+
console.error(
|
|
57817
|
+
`Warning: Could not read ${CODEX_CONFIG} \u2014 will create a new file.`
|
|
57818
|
+
);
|
|
57819
|
+
}
|
|
57820
|
+
}
|
|
57821
|
+
const installed = [];
|
|
57822
|
+
const warnings = [];
|
|
57823
|
+
if (target === "all" || target === "solutions") {
|
|
57824
|
+
const haansiBin = resolveHaansiBin();
|
|
57825
|
+
content = upsertTomlTable(content, "mcp_servers.haansi-solutions", {
|
|
57826
|
+
command: tomlString(haansiBin),
|
|
57827
|
+
args: tomlStringArray(["mcp-server"])
|
|
57828
|
+
});
|
|
57829
|
+
installed.push(`haansi-solutions (stdio \u2192 ${haansiBin} mcp-server)`);
|
|
57830
|
+
}
|
|
57831
|
+
if (target === "all" || target === "exchange") {
|
|
57832
|
+
const token = resolveToken2();
|
|
57833
|
+
if (!token) {
|
|
57834
|
+
warnings.push(
|
|
57835
|
+
"haansi-exchange not registered: no token found. Run `haansi auth login` first, or set HAANSI_TOKEN."
|
|
57836
|
+
);
|
|
57837
|
+
} else {
|
|
57838
|
+
const url2 = exchangeUrl();
|
|
57839
|
+
content = upsertTomlTable(content, "mcp_servers.haansi-exchange", {
|
|
57840
|
+
url: tomlString(url2),
|
|
57841
|
+
http_headers: tomlInlineTable({ Authorization: `Bearer ${token}` })
|
|
57842
|
+
});
|
|
57843
|
+
installed.push(`haansi-exchange (http \u2192 ${url2})`);
|
|
57398
57844
|
}
|
|
57399
57845
|
}
|
|
57400
|
-
(0,
|
|
57401
|
-
|
|
57846
|
+
(0, import_node_fs5.mkdirSync)(CODEX_HOME, { recursive: true });
|
|
57847
|
+
(0, import_node_fs5.writeFileSync)(CODEX_CONFIG, content, "utf-8");
|
|
57848
|
+
console.log(`
|
|
57849
|
+
OpenAI Codex \u2014 configured in ${CODEX_CONFIG}`);
|
|
57402
57850
|
for (const entry of installed) console.log(` \u2022 ${entry}`);
|
|
57403
57851
|
for (const w of warnings) console.log(` ! ${w}`);
|
|
57404
|
-
|
|
57852
|
+
return { installed, warnings };
|
|
57853
|
+
}
|
|
57854
|
+
async function setupMcp(targetArg, agentFlag) {
|
|
57855
|
+
const target = parseTarget(targetArg);
|
|
57856
|
+
const selection = resolveAgentSelection(agentFlag);
|
|
57857
|
+
for (const agentId of selection.agents) {
|
|
57858
|
+
WRITERS[agentId](target);
|
|
57859
|
+
}
|
|
57860
|
+
saveAgents(selection.agents);
|
|
57861
|
+
const restart = selection.agents.map((a) => a === "codex" ? "Codex" : "Claude Code").join(" / ");
|
|
57862
|
+
console.log(`
|
|
57863
|
+
Restart ${restart} to activate the changes.`);
|
|
57405
57864
|
}
|
|
57406
|
-
var
|
|
57865
|
+
var import_node_fs5, import_node_path4, import_node_os4, CLAUDE_JSON, CODEX_HOME, CODEX_CONFIG, WRITERS;
|
|
57407
57866
|
var init_setup_mcp = __esm({
|
|
57408
57867
|
"src/commands/setup-mcp.ts"() {
|
|
57409
57868
|
"use strict";
|
|
57410
|
-
|
|
57411
|
-
|
|
57412
|
-
|
|
57413
|
-
|
|
57414
|
-
|
|
57415
|
-
|
|
57416
|
-
|
|
57869
|
+
import_node_fs5 = require("node:fs");
|
|
57870
|
+
import_node_path4 = require("node:path");
|
|
57871
|
+
import_node_os4 = require("node:os");
|
|
57872
|
+
init_paths();
|
|
57873
|
+
init_agent_selection();
|
|
57874
|
+
init_codex_config();
|
|
57875
|
+
CLAUDE_JSON = (0, import_node_path4.join)((0, import_node_os4.homedir)(), ".claude.json");
|
|
57876
|
+
CODEX_HOME = process.env.CODEX_HOME || (0, import_node_path4.join)((0, import_node_os4.homedir)(), ".codex");
|
|
57877
|
+
CODEX_CONFIG = (0, import_node_path4.join)(CODEX_HOME, "config.toml");
|
|
57878
|
+
WRITERS = {
|
|
57879
|
+
"claude-code": setupClaudeMcp,
|
|
57880
|
+
codex: setupCodexMcp
|
|
57881
|
+
};
|
|
57417
57882
|
}
|
|
57418
57883
|
});
|
|
57419
57884
|
|
|
@@ -57463,7 +57928,7 @@ function buildPlist(haansiPath) {
|
|
|
57463
57928
|
}
|
|
57464
57929
|
async function setupDaemon(uninstall) {
|
|
57465
57930
|
if (uninstall) {
|
|
57466
|
-
if (!(0,
|
|
57931
|
+
if (!(0, import_node_fs6.existsSync)(PLIST_PATH)) {
|
|
57467
57932
|
console.log("Daemon is not installed.");
|
|
57468
57933
|
return;
|
|
57469
57934
|
}
|
|
@@ -57472,13 +57937,13 @@ async function setupDaemon(uninstall) {
|
|
|
57472
57937
|
} catch (err) {
|
|
57473
57938
|
console.error("Failed to unload daemon:", err);
|
|
57474
57939
|
}
|
|
57475
|
-
(0,
|
|
57940
|
+
(0, import_node_fs6.unlinkSync)(PLIST_PATH);
|
|
57476
57941
|
console.log("Daemon stopped and removed.");
|
|
57477
57942
|
return;
|
|
57478
57943
|
}
|
|
57479
57944
|
const haansiPath = findHaansiBin();
|
|
57480
|
-
(0,
|
|
57481
|
-
(0,
|
|
57945
|
+
(0, import_node_fs6.mkdirSync)((0, import_node_path5.join)((0, import_node_os5.homedir)(), ".haansi"), { recursive: true });
|
|
57946
|
+
(0, import_node_fs6.writeFileSync)(PLIST_PATH, buildPlist(haansiPath), "utf-8");
|
|
57482
57947
|
try {
|
|
57483
57948
|
(0, import_node_child_process3.spawnSync)("launchctl", ["unload", PLIST_PATH], { stdio: "pipe" });
|
|
57484
57949
|
} catch (err) {
|
|
@@ -57492,22 +57957,22 @@ async function setupDaemon(uninstall) {
|
|
|
57492
57957
|
The daemon will start automatically on every login.`);
|
|
57493
57958
|
console.log(`To uninstall: haansi setup-daemon --uninstall`);
|
|
57494
57959
|
}
|
|
57495
|
-
var import_node_child_process3,
|
|
57960
|
+
var import_node_child_process3, import_node_fs6, import_node_path5, import_node_os5, PLIST_LABEL, PLIST_PATH, LOG_FILE;
|
|
57496
57961
|
var init_setup_daemon = __esm({
|
|
57497
57962
|
"src/commands/setup-daemon.ts"() {
|
|
57498
57963
|
"use strict";
|
|
57499
57964
|
import_node_child_process3 = require("node:child_process");
|
|
57500
|
-
|
|
57501
|
-
|
|
57502
|
-
|
|
57965
|
+
import_node_fs6 = require("node:fs");
|
|
57966
|
+
import_node_path5 = require("node:path");
|
|
57967
|
+
import_node_os5 = require("node:os");
|
|
57503
57968
|
PLIST_LABEL = "co.haansi.daemon";
|
|
57504
|
-
PLIST_PATH = (0,
|
|
57505
|
-
(0,
|
|
57969
|
+
PLIST_PATH = (0, import_node_path5.join)(
|
|
57970
|
+
(0, import_node_os5.homedir)(),
|
|
57506
57971
|
"Library",
|
|
57507
57972
|
"LaunchAgents",
|
|
57508
57973
|
`${PLIST_LABEL}.plist`
|
|
57509
57974
|
);
|
|
57510
|
-
LOG_FILE = (0,
|
|
57975
|
+
LOG_FILE = (0, import_node_path5.join)((0, import_node_os5.homedir)(), ".haansi", "daemon.log");
|
|
57511
57976
|
}
|
|
57512
57977
|
});
|
|
57513
57978
|
|
|
@@ -57518,9 +57983,9 @@ __export(config_exports, {
|
|
|
57518
57983
|
});
|
|
57519
57984
|
function resolveToken4() {
|
|
57520
57985
|
if (process.env.HAANSI_TOKEN) return process.env.HAANSI_TOKEN;
|
|
57521
|
-
if ((0,
|
|
57986
|
+
if ((0, import_node_fs7.existsSync)(CREDENTIALS_FILE6)) {
|
|
57522
57987
|
try {
|
|
57523
|
-
const creds = JSON.parse((0,
|
|
57988
|
+
const creds = JSON.parse((0, import_node_fs7.readFileSync)(CREDENTIALS_FILE6, "utf-8"));
|
|
57524
57989
|
if (creds.token) return creds.token;
|
|
57525
57990
|
} catch (err) {
|
|
57526
57991
|
console.error("Failed to read credentials file:", err);
|
|
@@ -57537,12 +58002,12 @@ async function config5(args) {
|
|
|
57537
58002
|
process.exit(1);
|
|
57538
58003
|
return;
|
|
57539
58004
|
}
|
|
57540
|
-
const
|
|
58005
|
+
const apiUrl2 = process.env.HAANSI_API_URL ?? DEFAULT_API_URL6;
|
|
57541
58006
|
const subcommand = args[0];
|
|
57542
58007
|
if (subcommand === "get") {
|
|
57543
58008
|
const key = args[1];
|
|
57544
58009
|
const response = await fetch(
|
|
57545
|
-
`${
|
|
58010
|
+
`${apiUrl2}/api/v1/workspace/users/me/preferences`,
|
|
57546
58011
|
{
|
|
57547
58012
|
headers: { Authorization: `Bearer ${token}` }
|
|
57548
58013
|
}
|
|
@@ -57589,7 +58054,7 @@ async function config5(args) {
|
|
|
57589
58054
|
return;
|
|
57590
58055
|
}
|
|
57591
58056
|
const response = await fetch(
|
|
57592
|
-
`${
|
|
58057
|
+
`${apiUrl2}/api/v1/workspace/users/me/preferences`,
|
|
57593
58058
|
{
|
|
57594
58059
|
method: "PATCH",
|
|
57595
58060
|
headers: {
|
|
@@ -57618,15 +58083,15 @@ Supported keys:
|
|
|
57618
58083
|
if (subcommand !== void 0) process.exit(1);
|
|
57619
58084
|
}
|
|
57620
58085
|
}
|
|
57621
|
-
var
|
|
58086
|
+
var import_node_fs7, import_node_path6, import_node_os6, DEFAULT_API_URL6, CREDENTIALS_FILE6, VALID_SESSION_MODES;
|
|
57622
58087
|
var init_config = __esm({
|
|
57623
58088
|
"src/commands/config.ts"() {
|
|
57624
58089
|
"use strict";
|
|
57625
|
-
|
|
57626
|
-
|
|
57627
|
-
|
|
58090
|
+
import_node_fs7 = require("node:fs");
|
|
58091
|
+
import_node_path6 = require("node:path");
|
|
58092
|
+
import_node_os6 = require("node:os");
|
|
57628
58093
|
DEFAULT_API_URL6 = "https://api.haansi.co";
|
|
57629
|
-
CREDENTIALS_FILE6 = (0,
|
|
58094
|
+
CREDENTIALS_FILE6 = (0, import_node_path6.join)((0, import_node_os6.homedir)(), ".haansi", "credentials.json");
|
|
57630
58095
|
VALID_SESSION_MODES = ["private", "org"];
|
|
57631
58096
|
}
|
|
57632
58097
|
});
|
|
@@ -57640,9 +58105,9 @@ __export(list_exports, {
|
|
|
57640
58105
|
});
|
|
57641
58106
|
function resolveToken5() {
|
|
57642
58107
|
if (process.env.HAANSI_TOKEN) return process.env.HAANSI_TOKEN;
|
|
57643
|
-
if ((0,
|
|
58108
|
+
if ((0, import_node_fs8.existsSync)(CREDENTIALS_FILE7)) {
|
|
57644
58109
|
try {
|
|
57645
|
-
const creds = JSON.parse((0,
|
|
58110
|
+
const creds = JSON.parse((0, import_node_fs8.readFileSync)(CREDENTIALS_FILE7, "utf-8"));
|
|
57646
58111
|
if (creds.token) return creds.token;
|
|
57647
58112
|
} catch (err) {
|
|
57648
58113
|
console.error("Failed to read credentials file:", err);
|
|
@@ -57650,8 +58115,8 @@ function resolveToken5() {
|
|
|
57650
58115
|
}
|
|
57651
58116
|
throw new Error("No token found. Run `haansi init` first.");
|
|
57652
58117
|
}
|
|
57653
|
-
async function apiGet3(path, token,
|
|
57654
|
-
const response = await fetch(`${
|
|
58118
|
+
async function apiGet3(path, token, apiUrl2) {
|
|
58119
|
+
const response = await fetch(`${apiUrl2}/api/v1${path}`, {
|
|
57655
58120
|
headers: { Authorization: `Bearer ${token}` }
|
|
57656
58121
|
});
|
|
57657
58122
|
if (!response.ok) {
|
|
@@ -57660,8 +58125,8 @@ async function apiGet3(path, token, apiUrl) {
|
|
|
57660
58125
|
}
|
|
57661
58126
|
return response.json();
|
|
57662
58127
|
}
|
|
57663
|
-
async function apiPost2(path, body, token,
|
|
57664
|
-
const response = await fetch(`${
|
|
58128
|
+
async function apiPost2(path, body, token, apiUrl2) {
|
|
58129
|
+
const response = await fetch(`${apiUrl2}/api/v1${path}`, {
|
|
57665
58130
|
method: "POST",
|
|
57666
58131
|
headers: {
|
|
57667
58132
|
Authorization: `Bearer ${token}`,
|
|
@@ -57676,20 +58141,20 @@ async function apiPost2(path, body, token, apiUrl) {
|
|
|
57676
58141
|
return response.json();
|
|
57677
58142
|
}
|
|
57678
58143
|
async function list(options) {
|
|
57679
|
-
const
|
|
58144
|
+
const apiUrl2 = process.env.HAANSI_API_URL ?? DEFAULT_API_URL7;
|
|
57680
58145
|
const token = resolveToken5();
|
|
57681
58146
|
let data;
|
|
57682
58147
|
if (options.search) {
|
|
57683
58148
|
data = await apiGet3(
|
|
57684
58149
|
`/memory/solutions/search?q=${encodeURIComponent(options.search)}&top_k=${options.limit}`,
|
|
57685
58150
|
token,
|
|
57686
|
-
|
|
58151
|
+
apiUrl2
|
|
57687
58152
|
);
|
|
57688
58153
|
} else {
|
|
57689
58154
|
data = await apiGet3(
|
|
57690
58155
|
`/memory/solutions/recent?limit=${options.limit}`,
|
|
57691
58156
|
token,
|
|
57692
|
-
|
|
58157
|
+
apiUrl2
|
|
57693
58158
|
);
|
|
57694
58159
|
}
|
|
57695
58160
|
if (!data.results || data.results.length === 0) {
|
|
@@ -57702,13 +58167,13 @@ async function list(options) {
|
|
|
57702
58167
|
${data.results.length} result(s)`);
|
|
57703
58168
|
}
|
|
57704
58169
|
async function searchKnowledge(options) {
|
|
57705
|
-
const
|
|
58170
|
+
const apiUrl2 = process.env.HAANSI_API_URL ?? DEFAULT_API_URL7;
|
|
57706
58171
|
const token = resolveToken5();
|
|
57707
58172
|
let url2 = `/memory/solutions/knowledge/search?q=${encodeURIComponent(options.query)}&limit=${options.limit}`;
|
|
57708
58173
|
if (options.artifactType) {
|
|
57709
58174
|
url2 += `&artifact_type=${encodeURIComponent(options.artifactType)}`;
|
|
57710
58175
|
}
|
|
57711
|
-
const data = await apiGet3(url2, token,
|
|
58176
|
+
const data = await apiGet3(url2, token, apiUrl2);
|
|
57712
58177
|
if (!data.results || data.results.length === 0) {
|
|
57713
58178
|
console.log("No knowledge artifacts found matching your query.");
|
|
57714
58179
|
return;
|
|
@@ -57719,7 +58184,7 @@ async function searchKnowledge(options) {
|
|
|
57719
58184
|
${data.results.length} result(s)`);
|
|
57720
58185
|
}
|
|
57721
58186
|
async function saveKnowledge(options) {
|
|
57722
|
-
const
|
|
58187
|
+
const apiUrl2 = process.env.HAANSI_API_URL ?? DEFAULT_API_URL7;
|
|
57723
58188
|
const token = resolveToken5();
|
|
57724
58189
|
const body = {
|
|
57725
58190
|
problem_description: options.problem,
|
|
@@ -57733,28 +58198,32 @@ async function saveKnowledge(options) {
|
|
|
57733
58198
|
"/memory/solutions/mined",
|
|
57734
58199
|
body,
|
|
57735
58200
|
token,
|
|
57736
|
-
|
|
58201
|
+
apiUrl2
|
|
57737
58202
|
);
|
|
57738
58203
|
console.log("Knowledge saved successfully.");
|
|
57739
58204
|
console.log(` Problem: ${data.problem_description}`);
|
|
57740
58205
|
console.log(` Solution: ${data.solution_summary}`);
|
|
57741
58206
|
console.log("\nThis is now searchable via `haansi search-solutions`.");
|
|
57742
58207
|
}
|
|
57743
|
-
var
|
|
58208
|
+
var import_node_fs8, import_node_path7, import_node_os7, DEFAULT_API_URL7, CREDENTIALS_FILE7;
|
|
57744
58209
|
var init_list = __esm({
|
|
57745
58210
|
"src/commands/list.ts"() {
|
|
57746
58211
|
"use strict";
|
|
57747
|
-
|
|
57748
|
-
|
|
57749
|
-
|
|
58212
|
+
import_node_fs8 = require("node:fs");
|
|
58213
|
+
import_node_path7 = require("node:path");
|
|
58214
|
+
import_node_os7 = require("node:os");
|
|
57750
58215
|
DEFAULT_API_URL7 = "https://api.haansi.co";
|
|
57751
|
-
CREDENTIALS_FILE7 = (0,
|
|
58216
|
+
CREDENTIALS_FILE7 = (0, import_node_path7.join)((0, import_node_os7.homedir)(), ".haansi", "credentials.json");
|
|
57752
58217
|
}
|
|
57753
58218
|
});
|
|
57754
58219
|
|
|
57755
58220
|
// src/index.ts
|
|
57756
58221
|
var { version: VERSION } = require_package();
|
|
57757
58222
|
var command = process.argv[2];
|
|
58223
|
+
function getFlag(flag) {
|
|
58224
|
+
const idx = process.argv.indexOf(flag);
|
|
58225
|
+
return idx !== -1 ? process.argv[idx + 1] : void 0;
|
|
58226
|
+
}
|
|
57758
58227
|
async function run2() {
|
|
57759
58228
|
if (command === "--version" || command === "-v") {
|
|
57760
58229
|
console.log(VERSION);
|
|
@@ -57782,24 +58251,47 @@ Usage: haansi auth login`
|
|
|
57782
58251
|
}
|
|
57783
58252
|
case "collect": {
|
|
57784
58253
|
const { collect: collect2 } = await Promise.resolve().then(() => (init_collector(), collector_exports));
|
|
58254
|
+
const { resolveAgentSelection: resolveAgentSelection2 } = await Promise.resolve().then(() => (init_agent_selection(), agent_selection_exports));
|
|
57785
58255
|
const forceAll = process.argv.includes("--force-all");
|
|
57786
58256
|
const dryRun = process.argv.includes("--dry-run");
|
|
57787
58257
|
const limitIdx = process.argv.indexOf("--limit");
|
|
57788
58258
|
const limit = limitIdx !== -1 ? parseInt(process.argv[limitIdx + 1], 10) : void 0;
|
|
57789
|
-
const
|
|
58259
|
+
const agents = resolveAgentSelection2(getFlag("--agent")).agents;
|
|
57790
58260
|
const { uploaded, skipped, errors } = await collect2({
|
|
57791
58261
|
forceAll,
|
|
57792
58262
|
dryRun,
|
|
57793
58263
|
limit,
|
|
57794
|
-
|
|
58264
|
+
agents
|
|
57795
58265
|
});
|
|
57796
58266
|
console.log(
|
|
57797
58267
|
`
|
|
57798
|
-
Collector done: ${uploaded} uploaded, ${skipped} unchanged, ${errors} errors`
|
|
58268
|
+
Collector done (${agents.join(", ")}): ${uploaded} uploaded, ${skipped} unchanged, ${errors} errors`
|
|
57799
58269
|
);
|
|
57800
58270
|
if (errors > 0) process.exit(1);
|
|
57801
58271
|
break;
|
|
57802
58272
|
}
|
|
58273
|
+
case "agents": {
|
|
58274
|
+
const { detectInstalled: detectInstalled2, getAgents: getAgents2 } = await Promise.resolve().then(() => (init_agents(), agents_exports));
|
|
58275
|
+
const { resolveAgentSelection: resolveAgentSelection2 } = await Promise.resolve().then(() => (init_agent_selection(), agent_selection_exports));
|
|
58276
|
+
const installed = new Set(detectInstalled2().map((a) => a.id));
|
|
58277
|
+
const selection = resolveAgentSelection2();
|
|
58278
|
+
console.log("Supported coding agents:\n");
|
|
58279
|
+
for (const a of getAgents2()) {
|
|
58280
|
+
const flags = [
|
|
58281
|
+
installed.has(a.id) ? "installed" : "not detected",
|
|
58282
|
+
selection.agents.includes(a.id) ? "selected" : null
|
|
58283
|
+
].filter(Boolean);
|
|
58284
|
+
console.log(` \u2022 ${a.displayName} [${a.id}] \u2014 ${flags.join(", ")}`);
|
|
58285
|
+
}
|
|
58286
|
+
console.log(
|
|
58287
|
+
`
|
|
58288
|
+
Active selection (${selection.source}): ${selection.agents.join(", ")}`
|
|
58289
|
+
);
|
|
58290
|
+
console.log(
|
|
58291
|
+
"Change with `haansi setup-mcp --agent <claude|codex|both>` or `--agent` on collect."
|
|
58292
|
+
);
|
|
58293
|
+
break;
|
|
58294
|
+
}
|
|
57803
58295
|
case "daemon": {
|
|
57804
58296
|
await Promise.resolve().then(() => (init_collector_daemon(), collector_daemon_exports));
|
|
57805
58297
|
break;
|
|
@@ -57810,8 +58302,8 @@ Collector done: ${uploaded} uploaded, ${skipped} unchanged, ${errors} errors`
|
|
|
57810
58302
|
}
|
|
57811
58303
|
case "setup-mcp": {
|
|
57812
58304
|
const { setupMcp: setupMcp2 } = await Promise.resolve().then(() => (init_setup_mcp(), setup_mcp_exports));
|
|
57813
|
-
const targetArg = process.argv[3];
|
|
57814
|
-
await setupMcp2(targetArg);
|
|
58305
|
+
const targetArg = process.argv[3] && !process.argv[3].startsWith("--") ? process.argv[3] : void 0;
|
|
58306
|
+
await setupMcp2(targetArg, getFlag("--agent"));
|
|
57815
58307
|
break;
|
|
57816
58308
|
}
|
|
57817
58309
|
case "setup-daemon": {
|
|
@@ -57896,7 +58388,7 @@ Collector done: ${uploaded} uploaded, ${skipped} unchanged, ${errors} errors`
|
|
|
57896
58388
|
}
|
|
57897
58389
|
function printUsage() {
|
|
57898
58390
|
console.log(`
|
|
57899
|
-
Haansi CLI v${VERSION} \u2014 Session collector and MCP server for Claude Code
|
|
58391
|
+
Haansi CLI v${VERSION} \u2014 Session collector and MCP server for Claude Code & OpenAI Codex
|
|
57900
58392
|
|
|
57901
58393
|
Usage:
|
|
57902
58394
|
haansi <command> [options]
|
|
@@ -57904,7 +58396,8 @@ Usage:
|
|
|
57904
58396
|
Commands:
|
|
57905
58397
|
auth login Log in via browser (recommended)
|
|
57906
58398
|
init Authenticate with a token (for CI / headless)
|
|
57907
|
-
collect
|
|
58399
|
+
collect [--agent <sel>] Upload new/changed sessions once
|
|
58400
|
+
agents List supported / installed / selected agents
|
|
57908
58401
|
config get [key] Show your preferences (e.g. session_mode)
|
|
57909
58402
|
config set <key> <val> Update a preference
|
|
57910
58403
|
|
|
@@ -57914,8 +58407,11 @@ Commands:
|
|
|
57914
58407
|
save-knowledge Save a problem/solution for future retrieval
|
|
57915
58408
|
|
|
57916
58409
|
daemon Run the collector on a schedule (every 30 min)
|
|
57917
|
-
mcp-server Start the Haansi MCP server (used by
|
|
57918
|
-
setup-mcp [target]
|
|
58410
|
+
mcp-server Start the Haansi MCP server (used by the agent)
|
|
58411
|
+
setup-mcp [target] [--agent <sel>]
|
|
58412
|
+
Register MCP servers with a coding agent.
|
|
58413
|
+
Claude Code \u2192 ~/.claude.json; Codex \u2192 ~/.codex/config.toml
|
|
58414
|
+
agent: claude | codex | both (default: installed)
|
|
57919
58415
|
target: solutions | exchange | all (default: all)
|
|
57920
58416
|
- solutions: stdio, per-org search/save tools
|
|
57921
58417
|
- exchange: http, cross-org marketplace (read-only)
|
|
@@ -57924,6 +58420,7 @@ Commands:
|
|
|
57924
58420
|
|
|
57925
58421
|
Options:
|
|
57926
58422
|
--version, -v Show installed version
|
|
58423
|
+
--agent <sel> claude | codex | both (collect, setup-mcp)
|
|
57927
58424
|
--limit <n> Number of results (default: 5 for search, 10 for list)
|
|
57928
58425
|
|
|
57929
58426
|
Options for search-knowledge:
|
|
@@ -57937,6 +58434,7 @@ Options for save-knowledge:
|
|
|
57937
58434
|
--tags tag1,tag2 Comma-separated tags
|
|
57938
58435
|
|
|
57939
58436
|
Options for collect:
|
|
58437
|
+
--agent <sel> claude | codex | both (default: installed agents)
|
|
57940
58438
|
--force-all Re-upload all sessions, not just new ones
|
|
57941
58439
|
--dry-run Scan without uploading
|
|
57942
58440
|
--limit <n> Upload at most n sessions
|
|
@@ -57944,8 +58442,9 @@ Options for collect:
|
|
|
57944
58442
|
Environment variables:
|
|
57945
58443
|
HAANSI_TOKEN API token (or use \`haansi init\` to save it)
|
|
57946
58444
|
HAANSI_API_URL API base URL (default: https://api.haansi.co)
|
|
57947
|
-
|
|
57948
|
-
|
|
58445
|
+
CODEX_HOME Codex home dir (default: ~/.codex)
|
|
58446
|
+
HAANSI_AGENTS Daemon: comma-separated agents (claude-code,codex)
|
|
58447
|
+
HAANSI_COLLECT_SCHEDULE Cron expression for daemon (default: */30 * * * *)
|
|
57949
58448
|
`);
|
|
57950
58449
|
}
|
|
57951
58450
|
run2().catch((err) => {
|