haansi 0.1.8 → 0.1.10
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 +218 -19
- 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.10",
|
|
43
43
|
description: "Haansi CLI - Session collector and MCP server for Claude Code",
|
|
44
44
|
bin: {
|
|
45
45
|
haansi: "./dist/haansi.js"
|
|
@@ -557,6 +557,56 @@ function edgeScrub(content) {
|
|
|
557
557
|
}
|
|
558
558
|
return result;
|
|
559
559
|
}
|
|
560
|
+
function extractGitInfo(projectDir) {
|
|
561
|
+
const empty = {
|
|
562
|
+
gitRemoteUrl: null,
|
|
563
|
+
gitCommit: null,
|
|
564
|
+
gitBranch: null
|
|
565
|
+
};
|
|
566
|
+
const opts = { cwd: projectDir, timeout: 5e3, encoding: "utf-8" };
|
|
567
|
+
try {
|
|
568
|
+
(0, import_child_process.execSync)("git rev-parse --is-inside-work-tree", { ...opts, stdio: "pipe" });
|
|
569
|
+
} catch {
|
|
570
|
+
return empty;
|
|
571
|
+
}
|
|
572
|
+
const result = { ...empty };
|
|
573
|
+
try {
|
|
574
|
+
result.gitRemoteUrl = (0, import_child_process.execSync)("git remote get-url origin", {
|
|
575
|
+
...opts,
|
|
576
|
+
stdio: "pipe"
|
|
577
|
+
}).trim() || null;
|
|
578
|
+
} catch {
|
|
579
|
+
}
|
|
580
|
+
try {
|
|
581
|
+
result.gitCommit = (0, import_child_process.execSync)("git rev-parse HEAD", { ...opts, stdio: "pipe" }).trim() || null;
|
|
582
|
+
} catch {
|
|
583
|
+
}
|
|
584
|
+
try {
|
|
585
|
+
result.gitBranch = (0, import_child_process.execSync)("git rev-parse --abbrev-ref HEAD", {
|
|
586
|
+
...opts,
|
|
587
|
+
stdio: "pipe"
|
|
588
|
+
}).trim() || null;
|
|
589
|
+
} catch {
|
|
590
|
+
}
|
|
591
|
+
return result;
|
|
592
|
+
}
|
|
593
|
+
function extractCwdFromJsonl(filePath) {
|
|
594
|
+
try {
|
|
595
|
+
const content = (0, import_fs.readFileSync)(filePath, "utf-8");
|
|
596
|
+
const lines = content.split("\n").filter((l) => l.trim()).slice(0, 10);
|
|
597
|
+
for (const line of lines) {
|
|
598
|
+
try {
|
|
599
|
+
const entry = JSON.parse(line);
|
|
600
|
+
if (entry.cwd && typeof entry.cwd === "string") {
|
|
601
|
+
return entry.cwd;
|
|
602
|
+
}
|
|
603
|
+
} catch {
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
} catch {
|
|
607
|
+
}
|
|
608
|
+
return null;
|
|
609
|
+
}
|
|
560
610
|
function resolveToken() {
|
|
561
611
|
if (process.env.HAANSI_TOKEN) return process.env.HAANSI_TOKEN;
|
|
562
612
|
if ((0, import_fs.existsSync)(CREDENTIALS_FILE2)) {
|
|
@@ -627,16 +677,20 @@ async function getUploadedSessions(apiUrl, token) {
|
|
|
627
677
|
return /* @__PURE__ */ new Map();
|
|
628
678
|
}
|
|
629
679
|
}
|
|
630
|
-
async function uploadSession(sessionId, content, apiUrl, token) {
|
|
680
|
+
async function uploadSession(sessionId, content, apiUrl, token, gitInfo) {
|
|
631
681
|
const body = (0, import_zlib.gzipSync)(Buffer.from(content, "utf-8"));
|
|
682
|
+
const headers = {
|
|
683
|
+
Authorization: `Bearer ${token}`,
|
|
684
|
+
"Content-Type": "application/x-ndjson",
|
|
685
|
+
"Content-Encoding": "gzip",
|
|
686
|
+
"x-session-id": sessionId
|
|
687
|
+
};
|
|
688
|
+
if (gitInfo?.gitRemoteUrl) headers["x-git-remote-url"] = gitInfo.gitRemoteUrl;
|
|
689
|
+
if (gitInfo?.gitCommit) headers["x-git-commit"] = gitInfo.gitCommit;
|
|
690
|
+
if (gitInfo?.gitBranch) headers["x-git-branch"] = gitInfo.gitBranch;
|
|
632
691
|
const response = await fetch(`${apiUrl}/api/v1/sessions/raw`, {
|
|
633
692
|
method: "POST",
|
|
634
|
-
headers
|
|
635
|
-
Authorization: `Bearer ${token}`,
|
|
636
|
-
"Content-Type": "application/x-ndjson",
|
|
637
|
-
"Content-Encoding": "gzip",
|
|
638
|
-
"x-session-id": sessionId
|
|
639
|
-
},
|
|
693
|
+
headers,
|
|
640
694
|
body: new Uint8Array(body)
|
|
641
695
|
});
|
|
642
696
|
if (!response.ok) {
|
|
@@ -682,16 +736,25 @@ async function collect(options) {
|
|
|
682
736
|
try {
|
|
683
737
|
const rawContent = (0, import_fs.readFileSync)(session.filePath, "utf-8");
|
|
684
738
|
const scrubbed = edgeScrub(rawContent);
|
|
739
|
+
const cwd = extractCwdFromJsonl(session.filePath);
|
|
740
|
+
const gitInfo = cwd ? extractGitInfo(cwd) : { gitRemoteUrl: null, gitCommit: null, gitBranch: null };
|
|
685
741
|
if (options.dryRun) {
|
|
686
742
|
logger.info(
|
|
687
|
-
`[dry-run] Would upload ${shortId} (${session.lineCount} lines)
|
|
743
|
+
`[dry-run] Would upload ${shortId} (${session.lineCount} lines)`,
|
|
744
|
+
{
|
|
745
|
+
gitRemoteUrl: gitInfo.gitRemoteUrl,
|
|
746
|
+
gitCommit: gitInfo.gitCommit?.slice(0, 8)
|
|
747
|
+
}
|
|
688
748
|
);
|
|
689
749
|
uploaded++;
|
|
690
750
|
continue;
|
|
691
751
|
}
|
|
692
|
-
await uploadSession(session.sessionId, scrubbed, apiUrl, token);
|
|
752
|
+
await uploadSession(session.sessionId, scrubbed, apiUrl, token, gitInfo);
|
|
693
753
|
uploaded++;
|
|
694
|
-
logger.info(`Uploaded ${shortId} (${session.lineCount} lines)
|
|
754
|
+
logger.info(`Uploaded ${shortId} (${session.lineCount} lines)`, {
|
|
755
|
+
gitRemoteUrl: gitInfo.gitRemoteUrl,
|
|
756
|
+
gitCommit: gitInfo.gitCommit?.slice(0, 8)
|
|
757
|
+
});
|
|
695
758
|
} catch (err) {
|
|
696
759
|
errors++;
|
|
697
760
|
logger.error(`Failed to upload ${shortId}`, { err: err.message });
|
|
@@ -716,7 +779,7 @@ Collector done: ${uploaded} uploaded, ${skipped} unchanged, ${errors} errors`
|
|
|
716
779
|
);
|
|
717
780
|
if (errors > 0) process.exit(1);
|
|
718
781
|
}
|
|
719
|
-
var import_dotenv, import_path, import_fs, import_os, import_zlib, logger, DEFAULT_API_URL2, CREDENTIALS_FILE2, CLAUDE_PROJECTS_DIR, MIN_LINES, EDGE_SCRUB_PATTERNS;
|
|
782
|
+
var import_dotenv, import_path, import_fs, import_os, import_zlib, import_child_process, logger, DEFAULT_API_URL2, CREDENTIALS_FILE2, CLAUDE_PROJECTS_DIR, MIN_LINES, EDGE_SCRUB_PATTERNS;
|
|
720
783
|
var init_collector = __esm({
|
|
721
784
|
"../service-capture/claude-sessions/collector.ts"() {
|
|
722
785
|
"use strict";
|
|
@@ -725,6 +788,7 @@ var init_collector = __esm({
|
|
|
725
788
|
import_fs = require("fs");
|
|
726
789
|
import_os = require("os");
|
|
727
790
|
import_zlib = require("zlib");
|
|
791
|
+
import_child_process = require("child_process");
|
|
728
792
|
init_logger();
|
|
729
793
|
(0, import_dotenv.config)({ path: (0, import_path.resolve)(__dirname, "../../../.env") });
|
|
730
794
|
logger = createLogger("claude-collector");
|
|
@@ -1742,6 +1806,128 @@ var init_collector_daemon = __esm({
|
|
|
1742
1806
|
}
|
|
1743
1807
|
});
|
|
1744
1808
|
|
|
1809
|
+
// ../../packages/@company/types/src/knowledge.ts
|
|
1810
|
+
var init_knowledge = __esm({
|
|
1811
|
+
"../../packages/@company/types/src/knowledge.ts"() {
|
|
1812
|
+
"use strict";
|
|
1813
|
+
}
|
|
1814
|
+
});
|
|
1815
|
+
|
|
1816
|
+
// ../../packages/@company/types/src/user.ts
|
|
1817
|
+
var init_user = __esm({
|
|
1818
|
+
"../../packages/@company/types/src/user.ts"() {
|
|
1819
|
+
"use strict";
|
|
1820
|
+
}
|
|
1821
|
+
});
|
|
1822
|
+
|
|
1823
|
+
// ../../packages/@company/types/src/integration.ts
|
|
1824
|
+
var init_integration = __esm({
|
|
1825
|
+
"../../packages/@company/types/src/integration.ts"() {
|
|
1826
|
+
"use strict";
|
|
1827
|
+
}
|
|
1828
|
+
});
|
|
1829
|
+
|
|
1830
|
+
// ../../packages/@company/types/src/timeline.ts
|
|
1831
|
+
var init_timeline = __esm({
|
|
1832
|
+
"../../packages/@company/types/src/timeline.ts"() {
|
|
1833
|
+
"use strict";
|
|
1834
|
+
}
|
|
1835
|
+
});
|
|
1836
|
+
|
|
1837
|
+
// ../../packages/@company/types/src/artifact.ts
|
|
1838
|
+
var init_artifact = __esm({
|
|
1839
|
+
"../../packages/@company/types/src/artifact.ts"() {
|
|
1840
|
+
"use strict";
|
|
1841
|
+
}
|
|
1842
|
+
});
|
|
1843
|
+
|
|
1844
|
+
// ../../packages/@company/types/src/taxonomy.ts
|
|
1845
|
+
function normalizeSessionType(raw) {
|
|
1846
|
+
if (!raw) return "general";
|
|
1847
|
+
const lower = raw.toLowerCase().trim();
|
|
1848
|
+
if (lower in SESSION_TYPES) return lower;
|
|
1849
|
+
if (lower in SESSION_TYPE_ALIASES) return SESSION_TYPE_ALIASES[lower];
|
|
1850
|
+
return "general";
|
|
1851
|
+
}
|
|
1852
|
+
function normalizeComplexity(raw) {
|
|
1853
|
+
if (!raw) return "moderate";
|
|
1854
|
+
const lower = raw.toLowerCase().trim();
|
|
1855
|
+
if (lower in COMPLEXITIES) return lower;
|
|
1856
|
+
return "moderate";
|
|
1857
|
+
}
|
|
1858
|
+
var SESSION_TYPES, SESSION_TYPE_ALIASES, COMPLEXITIES;
|
|
1859
|
+
var init_taxonomy = __esm({
|
|
1860
|
+
"../../packages/@company/types/src/taxonomy.ts"() {
|
|
1861
|
+
"use strict";
|
|
1862
|
+
SESSION_TYPES = {
|
|
1863
|
+
debugging: {
|
|
1864
|
+
label: "Debugging",
|
|
1865
|
+
description: "Investigating and fixing bugs or errors"
|
|
1866
|
+
},
|
|
1867
|
+
feature_implementation: {
|
|
1868
|
+
label: "Feature Implementation",
|
|
1869
|
+
description: "Building new functionality or features"
|
|
1870
|
+
},
|
|
1871
|
+
code_review: {
|
|
1872
|
+
label: "Code Review",
|
|
1873
|
+
description: "Reviewing code for quality, correctness, or style"
|
|
1874
|
+
},
|
|
1875
|
+
deployment: {
|
|
1876
|
+
label: "Deployment",
|
|
1877
|
+
description: "Deploying, releasing, or provisioning infrastructure"
|
|
1878
|
+
},
|
|
1879
|
+
refactoring: {
|
|
1880
|
+
label: "Refactoring",
|
|
1881
|
+
description: "Restructuring existing code without changing behavior"
|
|
1882
|
+
},
|
|
1883
|
+
configuration: {
|
|
1884
|
+
label: "Configuration",
|
|
1885
|
+
description: "Setting up or modifying project/tool configuration"
|
|
1886
|
+
},
|
|
1887
|
+
question_answer: {
|
|
1888
|
+
label: "Question & Answer",
|
|
1889
|
+
description: "Asking or answering questions about code or systems"
|
|
1890
|
+
},
|
|
1891
|
+
general: {
|
|
1892
|
+
label: "General",
|
|
1893
|
+
description: "General-purpose session not fitting other categories"
|
|
1894
|
+
}
|
|
1895
|
+
};
|
|
1896
|
+
SESSION_TYPE_ALIASES = {
|
|
1897
|
+
bug_fix: "debugging",
|
|
1898
|
+
feature: "feature_implementation",
|
|
1899
|
+
refactor: "refactoring",
|
|
1900
|
+
config: "configuration"
|
|
1901
|
+
};
|
|
1902
|
+
COMPLEXITIES = {
|
|
1903
|
+
simple: {
|
|
1904
|
+
label: "Simple",
|
|
1905
|
+
description: "Straightforward task with few steps"
|
|
1906
|
+
},
|
|
1907
|
+
moderate: {
|
|
1908
|
+
label: "Moderate",
|
|
1909
|
+
description: "Multi-step task requiring some investigation"
|
|
1910
|
+
},
|
|
1911
|
+
complex: {
|
|
1912
|
+
label: "Complex",
|
|
1913
|
+
description: "Involved task with many steps or deep analysis"
|
|
1914
|
+
}
|
|
1915
|
+
};
|
|
1916
|
+
}
|
|
1917
|
+
});
|
|
1918
|
+
|
|
1919
|
+
// ../../packages/@company/types/src/index.ts
|
|
1920
|
+
var init_src = __esm({
|
|
1921
|
+
"../../packages/@company/types/src/index.ts"() {
|
|
1922
|
+
init_knowledge();
|
|
1923
|
+
init_user();
|
|
1924
|
+
init_integration();
|
|
1925
|
+
init_timeline();
|
|
1926
|
+
init_artifact();
|
|
1927
|
+
init_taxonomy();
|
|
1928
|
+
}
|
|
1929
|
+
});
|
|
1930
|
+
|
|
1745
1931
|
// ../../node_modules/zod/v3/helpers/util.js
|
|
1746
1932
|
var util, objectUtil, ZodParsedType, getParsedType;
|
|
1747
1933
|
var init_util = __esm({
|
|
@@ -56556,6 +56742,7 @@ var init_mcp_server2 = __esm({
|
|
|
56556
56742
|
import_fs2 = require("fs");
|
|
56557
56743
|
import_os2 = require("os");
|
|
56558
56744
|
init_collector();
|
|
56745
|
+
init_src();
|
|
56559
56746
|
init_mcp();
|
|
56560
56747
|
init_stdio2();
|
|
56561
56748
|
init_types2();
|
|
@@ -56666,7 +56853,9 @@ var init_mcp_server2 = __esm({
|
|
|
56666
56853
|
},
|
|
56667
56854
|
session_type: {
|
|
56668
56855
|
type: "string",
|
|
56669
|
-
description:
|
|
56856
|
+
description: `Type of session: ${Object.keys(SESSION_TYPES).map((t) => `"${t}"`).join(", ")} (default: "general"). Aliases: ${Object.entries(
|
|
56857
|
+
SESSION_TYPE_ALIASES
|
|
56858
|
+
).map(([k, v]) => `"${k}" -> "${v}"`).join(", ")}`
|
|
56670
56859
|
},
|
|
56671
56860
|
steps: {
|
|
56672
56861
|
type: "array",
|
|
@@ -56697,12 +56886,20 @@ var init_mcp_server2 = __esm({
|
|
|
56697
56886
|
},
|
|
56698
56887
|
complexity: {
|
|
56699
56888
|
type: "string",
|
|
56700
|
-
description:
|
|
56889
|
+
description: `${Object.keys(COMPLEXITIES).map((c) => `"${c}"`).join(", ")} (default: "moderate")`
|
|
56701
56890
|
},
|
|
56702
56891
|
project_path: {
|
|
56703
56892
|
type: "string",
|
|
56704
56893
|
description: "Project path or identifier"
|
|
56705
56894
|
},
|
|
56895
|
+
git_branch: {
|
|
56896
|
+
type: "string",
|
|
56897
|
+
description: "Current git branch name"
|
|
56898
|
+
},
|
|
56899
|
+
git_remote_url: {
|
|
56900
|
+
type: "string",
|
|
56901
|
+
description: "Git remote origin URL (e.g. github.com/org/repo)"
|
|
56902
|
+
},
|
|
56706
56903
|
tags: {
|
|
56707
56904
|
type: "array",
|
|
56708
56905
|
items: { type: "string" },
|
|
@@ -56832,6 +57029,8 @@ var init_mcp_server2 = __esm({
|
|
|
56832
57029
|
files_modified,
|
|
56833
57030
|
complexity,
|
|
56834
57031
|
project_path,
|
|
57032
|
+
git_branch,
|
|
57033
|
+
git_remote_url,
|
|
56835
57034
|
tags,
|
|
56836
57035
|
model,
|
|
56837
57036
|
source_tool,
|
|
@@ -56849,12 +57048,14 @@ var init_mcp_server2 = __esm({
|
|
|
56849
57048
|
{
|
|
56850
57049
|
problem_description,
|
|
56851
57050
|
solution_summary,
|
|
56852
|
-
session_type,
|
|
57051
|
+
session_type: normalizeSessionType(session_type),
|
|
56853
57052
|
steps,
|
|
56854
57053
|
tools_used,
|
|
56855
57054
|
files_modified,
|
|
56856
|
-
complexity,
|
|
57055
|
+
complexity: normalizeComplexity(complexity),
|
|
56857
57056
|
project_path,
|
|
57057
|
+
git_branch,
|
|
57058
|
+
git_remote_url,
|
|
56858
57059
|
tags,
|
|
56859
57060
|
model,
|
|
56860
57061
|
source_tool
|
|
@@ -56867,7 +57068,6 @@ var init_mcp_server2 = __esm({
|
|
|
56867
57068
|
type: "text",
|
|
56868
57069
|
text: [
|
|
56869
57070
|
"Solution saved successfully.",
|
|
56870
|
-
`ID: ${data.id}`,
|
|
56871
57071
|
`Problem: ${data.problem_description}`,
|
|
56872
57072
|
`Solution: ${data.solution_summary}`,
|
|
56873
57073
|
"This is now searchable via search_solutions."
|
|
@@ -57249,7 +57449,6 @@ async function saveKnowledge(options) {
|
|
|
57249
57449
|
if (options.tags) body.tags = options.tags;
|
|
57250
57450
|
const data = await apiPost2("/sessions/knowledge", body, token, apiUrl);
|
|
57251
57451
|
console.log("Knowledge saved successfully.");
|
|
57252
|
-
console.log(` ID: ${data.id}`);
|
|
57253
57452
|
console.log(` Problem: ${data.problem_description}`);
|
|
57254
57453
|
console.log(` Solution: ${data.solution_summary}`);
|
|
57255
57454
|
console.log("\nThis is now searchable via `haansi search-solutions`.");
|
|
@@ -57427,7 +57626,7 @@ Options for search-knowledge:
|
|
|
57427
57626
|
Options for save-knowledge:
|
|
57428
57627
|
--problem "description" Problem description (required)
|
|
57429
57628
|
--solution "summary" Solution summary (required)
|
|
57430
|
-
--type <session_type> Session type (
|
|
57629
|
+
--type <session_type> Session type (debugging, feature_implementation, code_review, deployment, refactoring, configuration, question_answer, general)
|
|
57431
57630
|
--complexity <level> simple, moderate, or complex
|
|
57432
57631
|
--tags tag1,tag2 Comma-separated tags
|
|
57433
57632
|
|