haansi 0.1.9 → 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.
Files changed (2) hide show
  1. package/dist/haansi.js +206 -19
  2. 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.9",
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: 'Type of session: "bug_fix", "feature", "refactor", "config", "general" (default: "general")'
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,7 +56886,7 @@ var init_mcp_server2 = __esm({
56697
56886
  },
56698
56887
  complexity: {
56699
56888
  type: "string",
56700
- description: '"simple", "moderate", or "complex" (default: "moderate")'
56889
+ description: `${Object.keys(COMPLEXITIES).map((c) => `"${c}"`).join(", ")} (default: "moderate")`
56701
56890
  },
56702
56891
  project_path: {
56703
56892
  type: "string",
@@ -56859,11 +57048,11 @@ var init_mcp_server2 = __esm({
56859
57048
  {
56860
57049
  problem_description,
56861
57050
  solution_summary,
56862
- session_type,
57051
+ session_type: normalizeSessionType(session_type),
56863
57052
  steps,
56864
57053
  tools_used,
56865
57054
  files_modified,
56866
- complexity,
57055
+ complexity: normalizeComplexity(complexity),
56867
57056
  project_path,
56868
57057
  git_branch,
56869
57058
  git_remote_url,
@@ -56879,7 +57068,6 @@ var init_mcp_server2 = __esm({
56879
57068
  type: "text",
56880
57069
  text: [
56881
57070
  "Solution saved successfully.",
56882
- `ID: ${data.id}`,
56883
57071
  `Problem: ${data.problem_description}`,
56884
57072
  `Solution: ${data.solution_summary}`,
56885
57073
  "This is now searchable via search_solutions."
@@ -57261,7 +57449,6 @@ async function saveKnowledge(options) {
57261
57449
  if (options.tags) body.tags = options.tags;
57262
57450
  const data = await apiPost2("/sessions/knowledge", body, token, apiUrl);
57263
57451
  console.log("Knowledge saved successfully.");
57264
- console.log(` ID: ${data.id}`);
57265
57452
  console.log(` Problem: ${data.problem_description}`);
57266
57453
  console.log(` Solution: ${data.solution_summary}`);
57267
57454
  console.log("\nThis is now searchable via `haansi search-solutions`.");
@@ -57439,7 +57626,7 @@ Options for search-knowledge:
57439
57626
  Options for save-knowledge:
57440
57627
  --problem "description" Problem description (required)
57441
57628
  --solution "summary" Solution summary (required)
57442
- --type <session_type> Session type (bug_fix, feature, refactor, general)
57629
+ --type <session_type> Session type (debugging, feature_implementation, code_review, deployment, refactoring, configuration, question_answer, general)
57443
57630
  --complexity <level> simple, moderate, or complex
57444
57631
  --tags tag1,tag2 Comma-separated tags
57445
57632
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "haansi",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "description": "Haansi CLI - Session collector and MCP server for Claude Code",
5
5
  "bin": {
6
6
  "haansi": "./dist/haansi.js"