haansi 0.1.17 → 0.1.19

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 +116 -45
  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.17",
42
+ version: "0.1.19",
43
43
  description: "Haansi CLI - Session collector and MCP server for Claude Code",
44
44
  bin: {
45
45
  haansi: "./dist/haansi.js"
@@ -1917,6 +1917,17 @@ var require_node_cron = __commonJS({
1917
1917
 
1918
1918
  // ../service-capture/claude-sessions/collector-daemon.ts
1919
1919
  var collector_daemon_exports = {};
1920
+ function getOnDiskVersion() {
1921
+ try {
1922
+ const realEntry = (0, import_fs2.realpathSync)(process.argv[1]);
1923
+ const pkgPath = (0, import_path2.resolve)((0, import_path2.dirname)(realEntry), "..", "package.json");
1924
+ if (!(0, import_fs2.existsSync)(pkgPath)) return null;
1925
+ const pkg = JSON.parse((0, import_fs2.readFileSync)(pkgPath, "utf-8"));
1926
+ return pkg.version ?? null;
1927
+ } catch {
1928
+ return null;
1929
+ }
1930
+ }
1920
1931
  async function run() {
1921
1932
  const projectPath = process.env.CLAUDE_PROJECT_PATH || void 0;
1922
1933
  logger2.info("Collect run starting", { projectPath: projectPath ?? "all" });
@@ -1934,9 +1945,20 @@ async function run() {
1934
1945
  }
1935
1946
  }
1936
1947
  async function main2() {
1937
- logger2.info("Collector daemon starting", { schedule: SCHEDULE });
1948
+ logger2.info("Collector daemon starting", {
1949
+ schedule: SCHEDULE,
1950
+ version: IN_MEMORY_VERSION
1951
+ });
1938
1952
  await run();
1939
1953
  import_node_cron.default.schedule(SCHEDULE, async () => {
1954
+ const diskVersion = getOnDiskVersion();
1955
+ if (diskVersion && diskVersion !== IN_MEMORY_VERSION) {
1956
+ logger2.info("Version mismatch detected \u2014 restarting", {
1957
+ inMemory: IN_MEMORY_VERSION,
1958
+ onDisk: diskVersion
1959
+ });
1960
+ process.exit(0);
1961
+ }
1940
1962
  logger2.info("Scheduled collect run triggered");
1941
1963
  await run();
1942
1964
  });
@@ -1948,17 +1970,19 @@ async function main2() {
1948
1970
  process.on("SIGTERM", () => shutdown("SIGTERM"));
1949
1971
  process.on("SIGINT", () => shutdown("SIGINT"));
1950
1972
  }
1951
- var import_dotenv2, import_path2, import_node_cron, logger2, SCHEDULE;
1973
+ var import_dotenv2, import_fs2, import_path2, import_node_cron, logger2, IN_MEMORY_VERSION, SCHEDULE;
1952
1974
  var init_collector_daemon = __esm({
1953
1975
  "../service-capture/claude-sessions/collector-daemon.ts"() {
1954
1976
  "use strict";
1955
1977
  import_dotenv2 = __toESM(require_main());
1978
+ import_fs2 = require("fs");
1956
1979
  import_path2 = require("path");
1957
1980
  import_node_cron = __toESM(require_node_cron());
1958
1981
  init_collector();
1959
1982
  init_logger();
1960
1983
  (0, import_dotenv2.config)({ path: (0, import_path2.resolve)(__dirname, "../../../.env") });
1961
1984
  logger2 = createLogger("collector-daemon");
1985
+ IN_MEMORY_VERSION = require_package().version;
1962
1986
  SCHEDULE = process.env.CLAUDE_COLLECT_SCHEDULE ?? "*/30 * * * *";
1963
1987
  main2().catch((err) => {
1964
1988
  logger2.error("Daemon failed to start", err);
@@ -50669,7 +50693,7 @@ var require_view = __commonJS({
50669
50693
  var debug = require_src()("express:view");
50670
50694
  var path = require("node:path");
50671
50695
  var fs = require("node:fs");
50672
- var dirname = path.dirname;
50696
+ var dirname2 = path.dirname;
50673
50697
  var basename2 = path.basename;
50674
50698
  var extname = path.extname;
50675
50699
  var join9 = path.join;
@@ -50708,7 +50732,7 @@ var require_view = __commonJS({
50708
50732
  for (var i = 0; i < roots.length && !path2; i++) {
50709
50733
  var root = roots[i];
50710
50734
  var loc = resolve4(root, name);
50711
- var dir = dirname(loc);
50735
+ var dir = dirname2(loc);
50712
50736
  var file2 = basename2(loc);
50713
50737
  path2 = this.resolve(dir, file2);
50714
50738
  }
@@ -56786,9 +56810,9 @@ var init_streamableHttp = __esm({
56786
56810
  var mcp_server_exports = {};
56787
56811
  function resolveToken2() {
56788
56812
  if (process.env.HAANSI_TOKEN) return process.env.HAANSI_TOKEN;
56789
- if ((0, import_fs2.existsSync)(CREDENTIALS_FILE4)) {
56813
+ if ((0, import_fs3.existsSync)(CREDENTIALS_FILE4)) {
56790
56814
  try {
56791
- const creds = JSON.parse((0, import_fs2.readFileSync)(CREDENTIALS_FILE4, "utf-8"));
56815
+ const creds = JSON.parse((0, import_fs3.readFileSync)(CREDENTIALS_FILE4, "utf-8"));
56792
56816
  if (creds.token) return creds.token;
56793
56817
  } catch {
56794
56818
  }
@@ -56872,13 +56896,13 @@ async function main3() {
56872
56896
  await mcpServer.connect(transport);
56873
56897
  }
56874
56898
  }
56875
- var import_dotenv3, import_path3, import_fs2, import_os2, DEFAULT_API_URL4, CREDENTIALS_FILE4, API_URL, TOKEN, contextSchema, isCollecting, lastCollectTime, COLLECT_COOLDOWN_MS, mcpServer, server;
56899
+ var import_dotenv3, import_path3, import_fs3, import_os2, DEFAULT_API_URL4, CREDENTIALS_FILE4, API_URL, TOKEN, contextSchema, isCollecting, lastCollectTime, COLLECT_COOLDOWN_MS, mcpServer, server;
56876
56900
  var init_mcp_server2 = __esm({
56877
56901
  "../service-capture/claude-sessions/mcp-server.ts"() {
56878
56902
  "use strict";
56879
56903
  import_dotenv3 = __toESM(require_main());
56880
56904
  import_path3 = require("path");
56881
- import_fs2 = require("fs");
56905
+ import_fs3 = require("fs");
56882
56906
  import_os2 = require("os");
56883
56907
  init_collector();
56884
56908
  init_src();
@@ -57194,7 +57218,26 @@ function resolveHaansiBin() {
57194
57218
  }
57195
57219
  return "haansi";
57196
57220
  }
57197
- async function setupMcp() {
57221
+ function resolveToken3() {
57222
+ if (process.env.HAANSI_TOKEN) return process.env.HAANSI_TOKEN;
57223
+ if ((0, import_node_fs3.existsSync)(CREDENTIALS_FILE5)) {
57224
+ try {
57225
+ const creds = JSON.parse((0, import_node_fs3.readFileSync)(CREDENTIALS_FILE5, "utf-8"));
57226
+ if (typeof creds.token === "string" && creds.token) return creds.token;
57227
+ } catch {
57228
+ }
57229
+ }
57230
+ return null;
57231
+ }
57232
+ function parseTarget(arg) {
57233
+ if (!arg || arg === "all") return "all";
57234
+ if (arg === "solutions" || arg === "exchange") return arg;
57235
+ throw new Error(
57236
+ `Unknown target: ${arg}. Use one of: solutions, exchange, all (default).`
57237
+ );
57238
+ }
57239
+ async function setupMcp(targetArg) {
57240
+ const target = parseTarget(targetArg);
57198
57241
  let config6 = {};
57199
57242
  if ((0, import_node_fs3.existsSync)(CLAUDE_JSON)) {
57200
57243
  try {
@@ -57205,22 +57248,44 @@ async function setupMcp() {
57205
57248
  );
57206
57249
  }
57207
57250
  }
57208
- if (!config6.mcpServers) {
57209
- config6.mcpServers = {};
57251
+ if (!config6.mcpServers) config6.mcpServers = {};
57252
+ const installed = [];
57253
+ const warnings = [];
57254
+ if (target === "all" || target === "solutions") {
57255
+ const haansiBin = resolveHaansiBin();
57256
+ config6.mcpServers["haansi-solutions"] = {
57257
+ command: haansiBin,
57258
+ args: ["mcp-server"]
57259
+ };
57260
+ installed.push(`haansi-solutions (stdio \u2192 ${haansiBin} mcp-server)`);
57261
+ }
57262
+ if (target === "all" || target === "exchange") {
57263
+ const token = resolveToken3();
57264
+ if (!token) {
57265
+ const msg = "haansi-exchange not registered: no token found. Run `haansi auth login` first, or set HAANSI_TOKEN.";
57266
+ if (target === "exchange") {
57267
+ console.error(msg);
57268
+ process.exit(1);
57269
+ }
57270
+ warnings.push(msg);
57271
+ } else {
57272
+ const apiUrl = process.env.HAANSI_API_URL ?? DEFAULT_API_URL5;
57273
+ const exchangeUrl = `${apiUrl.replace(/\/+$/, "")}/api/v1/mcp/exchange`;
57274
+ config6.mcpServers["haansi-exchange"] = {
57275
+ type: "http",
57276
+ url: exchangeUrl,
57277
+ headers: { Authorization: `Bearer ${token}` }
57278
+ };
57279
+ installed.push(`haansi-exchange (http \u2192 ${exchangeUrl})`);
57280
+ }
57210
57281
  }
57211
- const haansiBin = resolveHaansiBin();
57212
- config6.mcpServers["haansi-solutions"] = {
57213
- command: haansiBin,
57214
- args: ["mcp-server"]
57215
- };
57216
57282
  (0, import_node_fs3.writeFileSync)(CLAUDE_JSON, JSON.stringify(config6, null, 2) + "\n", "utf-8");
57217
- console.log(`MCP server configured in ${CLAUDE_JSON}`);
57218
- console.log(` command: ${haansiBin} mcp-server`);
57219
- console.log(
57220
- "\nRestart Claude Code to activate the haansi-solutions MCP server."
57221
- );
57283
+ console.log(`MCP servers configured in ${CLAUDE_JSON}`);
57284
+ for (const entry of installed) console.log(` \u2022 ${entry}`);
57285
+ for (const w of warnings) console.log(` ! ${w}`);
57286
+ console.log("\nRestart Claude Code to activate the changes.");
57222
57287
  }
57223
- var import_node_fs3, import_node_path3, import_node_os3, import_node_child_process2, CLAUDE_JSON;
57288
+ var import_node_fs3, import_node_path3, import_node_os3, import_node_child_process2, CLAUDE_JSON, CREDENTIALS_FILE5, DEFAULT_API_URL5;
57224
57289
  var init_setup_mcp = __esm({
57225
57290
  "src/commands/setup-mcp.ts"() {
57226
57291
  "use strict";
@@ -57229,6 +57294,8 @@ var init_setup_mcp = __esm({
57229
57294
  import_node_os3 = require("node:os");
57230
57295
  import_node_child_process2 = require("node:child_process");
57231
57296
  CLAUDE_JSON = (0, import_node_path3.join)((0, import_node_os3.homedir)(), ".claude.json");
57297
+ CREDENTIALS_FILE5 = (0, import_node_path3.join)((0, import_node_os3.homedir)(), ".haansi", "credentials.json");
57298
+ DEFAULT_API_URL5 = "https://api.haansi.co";
57232
57299
  }
57233
57300
  });
57234
57301
 
@@ -57331,11 +57398,11 @@ var config_exports = {};
57331
57398
  __export(config_exports, {
57332
57399
  config: () => config5
57333
57400
  });
57334
- function resolveToken3() {
57401
+ function resolveToken4() {
57335
57402
  if (process.env.HAANSI_TOKEN) return process.env.HAANSI_TOKEN;
57336
- if ((0, import_node_fs5.existsSync)(CREDENTIALS_FILE5)) {
57403
+ if ((0, import_node_fs5.existsSync)(CREDENTIALS_FILE6)) {
57337
57404
  try {
57338
- const creds = JSON.parse((0, import_node_fs5.readFileSync)(CREDENTIALS_FILE5, "utf-8"));
57405
+ const creds = JSON.parse((0, import_node_fs5.readFileSync)(CREDENTIALS_FILE6, "utf-8"));
57339
57406
  if (creds.token) return creds.token;
57340
57407
  } catch (err) {
57341
57408
  console.error("Failed to read credentials file:", err);
@@ -57344,7 +57411,7 @@ function resolveToken3() {
57344
57411
  return null;
57345
57412
  }
57346
57413
  async function config5(args) {
57347
- const token = resolveToken3();
57414
+ const token = resolveToken4();
57348
57415
  if (!token) {
57349
57416
  console.error(
57350
57417
  "Error: No token found. Run `haansi init` or set HAANSI_TOKEN."
@@ -57352,7 +57419,7 @@ async function config5(args) {
57352
57419
  process.exit(1);
57353
57420
  return;
57354
57421
  }
57355
- const apiUrl = process.env.HAANSI_API_URL ?? DEFAULT_API_URL5;
57422
+ const apiUrl = process.env.HAANSI_API_URL ?? DEFAULT_API_URL6;
57356
57423
  const subcommand = args[0];
57357
57424
  if (subcommand === "get") {
57358
57425
  const key = args[1];
@@ -57427,15 +57494,15 @@ Supported keys:
57427
57494
  if (subcommand !== void 0) process.exit(1);
57428
57495
  }
57429
57496
  }
57430
- var import_node_fs5, import_node_path5, import_node_os5, DEFAULT_API_URL5, CREDENTIALS_FILE5, VALID_SESSION_MODES;
57497
+ var import_node_fs5, import_node_path5, import_node_os5, DEFAULT_API_URL6, CREDENTIALS_FILE6, VALID_SESSION_MODES;
57431
57498
  var init_config = __esm({
57432
57499
  "src/commands/config.ts"() {
57433
57500
  "use strict";
57434
57501
  import_node_fs5 = require("node:fs");
57435
57502
  import_node_path5 = require("node:path");
57436
57503
  import_node_os5 = require("node:os");
57437
- DEFAULT_API_URL5 = "https://api.haansi.co";
57438
- CREDENTIALS_FILE5 = (0, import_node_path5.join)((0, import_node_os5.homedir)(), ".haansi", "credentials.json");
57504
+ DEFAULT_API_URL6 = "https://api.haansi.co";
57505
+ CREDENTIALS_FILE6 = (0, import_node_path5.join)((0, import_node_os5.homedir)(), ".haansi", "credentials.json");
57439
57506
  VALID_SESSION_MODES = ["private", "org"];
57440
57507
  }
57441
57508
  });
@@ -57447,11 +57514,11 @@ __export(list_exports, {
57447
57514
  saveKnowledge: () => saveKnowledge,
57448
57515
  searchKnowledge: () => searchKnowledge
57449
57516
  });
57450
- function resolveToken4() {
57517
+ function resolveToken5() {
57451
57518
  if (process.env.HAANSI_TOKEN) return process.env.HAANSI_TOKEN;
57452
- if ((0, import_node_fs6.existsSync)(CREDENTIALS_FILE6)) {
57519
+ if ((0, import_node_fs6.existsSync)(CREDENTIALS_FILE7)) {
57453
57520
  try {
57454
- const creds = JSON.parse((0, import_node_fs6.readFileSync)(CREDENTIALS_FILE6, "utf-8"));
57521
+ const creds = JSON.parse((0, import_node_fs6.readFileSync)(CREDENTIALS_FILE7, "utf-8"));
57455
57522
  if (creds.token) return creds.token;
57456
57523
  } catch (err) {
57457
57524
  console.error("Failed to read credentials file:", err);
@@ -57485,8 +57552,8 @@ async function apiPost2(path, body, token, apiUrl) {
57485
57552
  return response.json();
57486
57553
  }
57487
57554
  async function list(options) {
57488
- const apiUrl = process.env.HAANSI_API_URL ?? DEFAULT_API_URL6;
57489
- const token = resolveToken4();
57555
+ const apiUrl = process.env.HAANSI_API_URL ?? DEFAULT_API_URL7;
57556
+ const token = resolveToken5();
57490
57557
  let data;
57491
57558
  if (options.search) {
57492
57559
  data = await apiGet3(
@@ -57511,8 +57578,8 @@ async function list(options) {
57511
57578
  ${data.results.length} result(s)`);
57512
57579
  }
57513
57580
  async function searchKnowledge(options) {
57514
- const apiUrl = process.env.HAANSI_API_URL ?? DEFAULT_API_URL6;
57515
- const token = resolveToken4();
57581
+ const apiUrl = process.env.HAANSI_API_URL ?? DEFAULT_API_URL7;
57582
+ const token = resolveToken5();
57516
57583
  let url2 = `/sessions/knowledge/search?q=${encodeURIComponent(options.query)}&limit=${options.limit}`;
57517
57584
  if (options.artifactType) {
57518
57585
  url2 += `&artifact_type=${encodeURIComponent(options.artifactType)}`;
@@ -57528,8 +57595,8 @@ async function searchKnowledge(options) {
57528
57595
  ${data.results.length} result(s)`);
57529
57596
  }
57530
57597
  async function saveKnowledge(options) {
57531
- const apiUrl = process.env.HAANSI_API_URL ?? DEFAULT_API_URL6;
57532
- const token = resolveToken4();
57598
+ const apiUrl = process.env.HAANSI_API_URL ?? DEFAULT_API_URL7;
57599
+ const token = resolveToken5();
57533
57600
  const body = {
57534
57601
  problem_description: options.problem,
57535
57602
  solution_summary: options.solution,
@@ -57544,15 +57611,15 @@ async function saveKnowledge(options) {
57544
57611
  console.log(` Solution: ${data.solution_summary}`);
57545
57612
  console.log("\nThis is now searchable via `haansi search-solutions`.");
57546
57613
  }
57547
- var import_node_fs6, import_node_path6, import_node_os6, DEFAULT_API_URL6, CREDENTIALS_FILE6;
57614
+ var import_node_fs6, import_node_path6, import_node_os6, DEFAULT_API_URL7, CREDENTIALS_FILE7;
57548
57615
  var init_list = __esm({
57549
57616
  "src/commands/list.ts"() {
57550
57617
  "use strict";
57551
57618
  import_node_fs6 = require("node:fs");
57552
57619
  import_node_path6 = require("node:path");
57553
57620
  import_node_os6 = require("node:os");
57554
- DEFAULT_API_URL6 = "https://api.haansi.co";
57555
- CREDENTIALS_FILE6 = (0, import_node_path6.join)((0, import_node_os6.homedir)(), ".haansi", "credentials.json");
57621
+ DEFAULT_API_URL7 = "https://api.haansi.co";
57622
+ CREDENTIALS_FILE7 = (0, import_node_path6.join)((0, import_node_os6.homedir)(), ".haansi", "credentials.json");
57556
57623
  }
57557
57624
  });
57558
57625
 
@@ -57614,7 +57681,8 @@ Collector done: ${uploaded} uploaded, ${skipped} unchanged, ${errors} errors`
57614
57681
  }
57615
57682
  case "setup-mcp": {
57616
57683
  const { setupMcp: setupMcp2 } = await Promise.resolve().then(() => (init_setup_mcp(), setup_mcp_exports));
57617
- await setupMcp2();
57684
+ const targetArg = process.argv[3];
57685
+ await setupMcp2(targetArg);
57618
57686
  break;
57619
57687
  }
57620
57688
  case "setup-daemon": {
@@ -57718,7 +57786,10 @@ Commands:
57718
57786
 
57719
57787
  daemon Run the collector on a schedule (every 30 min)
57720
57788
  mcp-server Start the Haansi MCP server (used by Claude Code)
57721
- setup-mcp Add haansi-solutions MCP entry to ~/.claude.json
57789
+ setup-mcp [target] Register MCP servers in ~/.claude.json
57790
+ target: solutions | exchange | all (default: all)
57791
+ - solutions: stdio, per-org search/save tools
57792
+ - exchange: http, cross-org marketplace (read-only)
57722
57793
  setup-daemon Install launchd service to auto-start daemon on login (macOS)
57723
57794
  help Show this help message
57724
57795
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "haansi",
3
- "version": "0.1.17",
3
+ "version": "0.1.19",
4
4
  "description": "Haansi CLI - Session collector and MCP server for Claude Code",
5
5
  "bin": {
6
6
  "haansi": "./dist/haansi.js"