haansi 0.1.7 → 0.1.8

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 +168 -26
  2. package/package.json +1 -1
package/dist/haansi.js CHANGED
@@ -34,6 +34,36 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
34
34
  ));
35
35
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
36
36
 
37
+ // package.json
38
+ var require_package = __commonJS({
39
+ "package.json"(exports2, module2) {
40
+ module2.exports = {
41
+ name: "haansi",
42
+ version: "0.1.8",
43
+ description: "Haansi CLI - Session collector and MCP server for Claude Code",
44
+ bin: {
45
+ haansi: "./dist/haansi.js"
46
+ },
47
+ files: [
48
+ "dist/",
49
+ "README.md"
50
+ ],
51
+ scripts: {
52
+ build: "node build.mjs",
53
+ prepublishOnly: "npm run build"
54
+ },
55
+ devDependencies: {
56
+ esbuild: "^0.27.0",
57
+ typescript: "^5.7.2",
58
+ "@types/node": "^22.10.1"
59
+ },
60
+ engines: {
61
+ node: ">=18.0.0"
62
+ }
63
+ };
64
+ }
65
+ });
66
+
37
67
  // src/commands/init.ts
38
68
  var init_exports = {};
39
69
  __export(init_exports, {
@@ -106,7 +136,7 @@ var init_init = __esm({
106
136
  });
107
137
 
108
138
  // ../../node_modules/dotenv/package.json
109
- var require_package = __commonJS({
139
+ var require_package2 = __commonJS({
110
140
  "../../node_modules/dotenv/package.json"(exports2, module2) {
111
141
  module2.exports = {
112
142
  name: "dotenv",
@@ -180,7 +210,7 @@ var require_main = __commonJS({
180
210
  var path = require("path");
181
211
  var os = require("os");
182
212
  var crypto6 = require("crypto");
183
- var packageJson = require_package();
213
+ var packageJson = require_package2();
184
214
  var version3 = packageJson.version;
185
215
  var LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg;
186
216
  function parse4(src) {
@@ -57123,7 +57153,9 @@ var init_config = __esm({
57123
57153
  // src/commands/list.ts
57124
57154
  var list_exports = {};
57125
57155
  __export(list_exports, {
57126
- list: () => list
57156
+ list: () => list,
57157
+ saveKnowledge: () => saveKnowledge,
57158
+ searchKnowledge: () => searchKnowledge
57127
57159
  });
57128
57160
  function resolveToken4() {
57129
57161
  if (process.env.HAANSI_TOKEN) return process.env.HAANSI_TOKEN;
@@ -57146,6 +57178,21 @@ async function apiGet3(path, token, apiUrl) {
57146
57178
  }
57147
57179
  return response.json();
57148
57180
  }
57181
+ async function apiPost2(path, body, token, apiUrl) {
57182
+ const response = await fetch(`${apiUrl}/api/v1${path}`, {
57183
+ method: "POST",
57184
+ headers: {
57185
+ Authorization: `Bearer ${token}`,
57186
+ "Content-Type": "application/json"
57187
+ },
57188
+ body: JSON.stringify(body)
57189
+ });
57190
+ if (!response.ok) {
57191
+ const text = await response.text().catch(() => "");
57192
+ throw new Error(`API error ${response.status}: ${text.slice(0, 200)}`);
57193
+ }
57194
+ return response.json();
57195
+ }
57149
57196
  async function list(options) {
57150
57197
  const apiUrl = process.env.HAANSI_API_URL ?? DEFAULT_API_URL5;
57151
57198
  const token = resolveToken4();
@@ -57172,6 +57219,41 @@ async function list(options) {
57172
57219
  console.log(`
57173
57220
  ${data.results.length} result(s)`);
57174
57221
  }
57222
+ async function searchKnowledge(options) {
57223
+ const apiUrl = process.env.HAANSI_API_URL ?? DEFAULT_API_URL5;
57224
+ const token = resolveToken4();
57225
+ let url2 = `/sessions/knowledge/search?q=${encodeURIComponent(options.query)}&limit=${options.limit}`;
57226
+ if (options.artifactType) {
57227
+ url2 += `&artifact_type=${encodeURIComponent(options.artifactType)}`;
57228
+ }
57229
+ const data = await apiGet3(url2, token, apiUrl);
57230
+ if (!data.results || data.results.length === 0) {
57231
+ console.log("No knowledge artifacts found matching your query.");
57232
+ return;
57233
+ }
57234
+ const separator = "\n" + "\u2500".repeat(60) + "\n";
57235
+ console.log(data.results.join(separator));
57236
+ console.log(`
57237
+ ${data.results.length} result(s)`);
57238
+ }
57239
+ async function saveKnowledge(options) {
57240
+ const apiUrl = process.env.HAANSI_API_URL ?? DEFAULT_API_URL5;
57241
+ const token = resolveToken4();
57242
+ const body = {
57243
+ problem_description: options.problem,
57244
+ solution_summary: options.solution,
57245
+ source_tool: "haansi-cli"
57246
+ };
57247
+ if (options.sessionType) body.session_type = options.sessionType;
57248
+ if (options.complexity) body.complexity = options.complexity;
57249
+ if (options.tags) body.tags = options.tags;
57250
+ const data = await apiPost2("/sessions/knowledge", body, token, apiUrl);
57251
+ console.log("Knowledge saved successfully.");
57252
+ console.log(` ID: ${data.id}`);
57253
+ console.log(` Problem: ${data.problem_description}`);
57254
+ console.log(` Solution: ${data.solution_summary}`);
57255
+ console.log("\nThis is now searchable via `haansi search-solutions`.");
57256
+ }
57175
57257
  var import_node_fs5, import_node_path5, import_node_os5, DEFAULT_API_URL5, CREDENTIALS_FILE5;
57176
57258
  var init_list = __esm({
57177
57259
  "src/commands/list.ts"() {
@@ -57185,8 +57267,13 @@ var init_list = __esm({
57185
57267
  });
57186
57268
 
57187
57269
  // src/index.ts
57270
+ var { version: VERSION } = require_package();
57188
57271
  var command = process.argv[2];
57189
57272
  async function run2() {
57273
+ if (command === "--version" || command === "-v") {
57274
+ console.log(VERSION);
57275
+ return;
57276
+ }
57190
57277
  switch (command) {
57191
57278
  case "init": {
57192
57279
  const { init: init2 } = await Promise.resolve().then(() => (init_init(), init_exports));
@@ -57237,11 +57324,13 @@ Collector done: ${uploaded} uploaded, ${skipped} unchanged, ${errors} errors`
57237
57324
  await config6(process.argv.slice(3));
57238
57325
  break;
57239
57326
  }
57327
+ // ── Solution & Knowledge commands (consistent with MCP tool names) ──
57328
+ case "search-solutions":
57240
57329
  case "search": {
57241
57330
  const { list: list2 } = await Promise.resolve().then(() => (init_list(), list_exports));
57242
57331
  const query = process.argv[3];
57243
57332
  if (!query || query.startsWith("--")) {
57244
- console.error("Usage: haansi search <query> [--limit <n>]");
57333
+ console.error("Usage: haansi search-solutions <query> [--limit <n>]");
57245
57334
  process.exit(1);
57246
57335
  }
57247
57336
  const limitIdx = process.argv.indexOf("--limit");
@@ -57249,6 +57338,7 @@ Collector done: ${uploaded} uploaded, ${skipped} unchanged, ${errors} errors`
57249
57338
  await list2({ search: query, limit });
57250
57339
  break;
57251
57340
  }
57341
+ case "list-solutions":
57252
57342
  case "list": {
57253
57343
  const { list: list2 } = await Promise.resolve().then(() => (init_list(), list_exports));
57254
57344
  const searchIdx = process.argv.indexOf("--search");
@@ -57258,6 +57348,43 @@ Collector done: ${uploaded} uploaded, ${skipped} unchanged, ${errors} errors`
57258
57348
  await list2({ search, limit });
57259
57349
  break;
57260
57350
  }
57351
+ case "search-knowledge": {
57352
+ const { searchKnowledge: searchKnowledge2 } = await Promise.resolve().then(() => (init_list(), list_exports));
57353
+ const query = process.argv[3];
57354
+ if (!query || query.startsWith("--")) {
57355
+ console.error(
57356
+ "Usage: haansi search-knowledge <query> [--type <artifact_type>] [--limit <n>]"
57357
+ );
57358
+ process.exit(1);
57359
+ }
57360
+ const typeIdx = process.argv.indexOf("--type");
57361
+ const artifactType = typeIdx !== -1 ? process.argv[typeIdx + 1] : void 0;
57362
+ const limitIdx = process.argv.indexOf("--limit");
57363
+ const limit = limitIdx !== -1 ? parseInt(process.argv[limitIdx + 1], 10) : 10;
57364
+ await searchKnowledge2({ query, artifactType, limit });
57365
+ break;
57366
+ }
57367
+ case "save-knowledge": {
57368
+ const { saveKnowledge: saveKnowledge2 } = await Promise.resolve().then(() => (init_list(), list_exports));
57369
+ const problemIdx = process.argv.indexOf("--problem");
57370
+ const solutionIdx = process.argv.indexOf("--solution");
57371
+ if (problemIdx === -1 || solutionIdx === -1) {
57372
+ console.error(
57373
+ 'Usage: haansi save-knowledge --problem "description" --solution "summary" [--type <session_type>] [--complexity <simple|moderate|complex>] [--tags tag1,tag2]'
57374
+ );
57375
+ process.exit(1);
57376
+ }
57377
+ const problem = process.argv[problemIdx + 1];
57378
+ const solution = process.argv[solutionIdx + 1];
57379
+ const typeIdx = process.argv.indexOf("--type");
57380
+ const sessionType = typeIdx !== -1 ? process.argv[typeIdx + 1] : void 0;
57381
+ const complexityIdx = process.argv.indexOf("--complexity");
57382
+ const complexity = complexityIdx !== -1 ? process.argv[complexityIdx + 1] : void 0;
57383
+ const tagsIdx = process.argv.indexOf("--tags");
57384
+ const tags = tagsIdx !== -1 ? process.argv[tagsIdx + 1].split(",") : void 0;
57385
+ await saveKnowledge2({ problem, solution, sessionType, complexity, tags });
57386
+ break;
57387
+ }
57261
57388
  case "help":
57262
57389
  default: {
57263
57390
  printUsage();
@@ -57268,37 +57395,52 @@ Collector done: ${uploaded} uploaded, ${skipped} unchanged, ${errors} errors`
57268
57395
  }
57269
57396
  function printUsage() {
57270
57397
  console.log(`
57271
- Haansi CLI \u2014 Session collector and MCP server for Claude Code
57398
+ Haansi CLI v${VERSION} \u2014 Session collector and MCP server for Claude Code
57272
57399
 
57273
57400
  Usage:
57274
57401
  haansi <command> [options]
57275
57402
 
57276
57403
  Commands:
57277
- init Authenticate and save your API token
57278
- collect Upload new/changed Claude sessions once
57279
- config get [key] Show your preferences (e.g. session_mode)
57280
- config set <key> <val> Update a preference
57281
- search <query> Semantic search over mined solutions
57282
- list List recent mined solutions
57283
- daemon Run the collector on a schedule (every 30 min)
57284
- mcp-server Start the Haansi MCP server (used by Claude Code)
57285
- setup-mcp Add haansi-solutions MCP entry to ~/.claude.json
57286
- setup-daemon Install launchd service to auto-start daemon on login (macOS)
57287
- help Show this help message
57288
-
57289
- Options for search/list:
57290
- --limit <n> Number of results (default: 5 for search, 10 for list)
57404
+ init Authenticate and save your API token
57405
+ collect Upload new/changed Claude sessions once
57406
+ config get [key] Show your preferences (e.g. session_mode)
57407
+ config set <key> <val> Update a preference
57408
+
57409
+ search-solutions <query> Semantic search over mined solutions
57410
+ list-solutions List recent mined solutions
57411
+ search-knowledge <query> Search knowledge artifacts (cards, decisions, etc.)
57412
+ save-knowledge Save a problem/solution for future retrieval
57413
+
57414
+ daemon Run the collector on a schedule (every 30 min)
57415
+ mcp-server Start the Haansi MCP server (used by Claude Code)
57416
+ setup-mcp Add haansi-solutions MCP entry to ~/.claude.json
57417
+ setup-daemon Install launchd service to auto-start daemon on login (macOS)
57418
+ help Show this help message
57419
+
57420
+ Options:
57421
+ --version, -v Show installed version
57422
+ --limit <n> Number of results (default: 5 for search, 10 for list)
57423
+
57424
+ Options for search-knowledge:
57425
+ --type <artifact_type> Filter by type (knowledge_card, decision_record, etc.)
57426
+
57427
+ Options for save-knowledge:
57428
+ --problem "description" Problem description (required)
57429
+ --solution "summary" Solution summary (required)
57430
+ --type <session_type> Session type (bug_fix, feature, refactor, general)
57431
+ --complexity <level> simple, moderate, or complex
57432
+ --tags tag1,tag2 Comma-separated tags
57291
57433
 
57292
57434
  Options for collect:
57293
- --force-all Re-upload all sessions, not just new ones
57294
- --dry-run Scan without uploading
57295
- --limit <n> Upload at most n sessions
57435
+ --force-all Re-upload all sessions, not just new ones
57436
+ --dry-run Scan without uploading
57437
+ --limit <n> Upload at most n sessions
57296
57438
 
57297
57439
  Environment variables:
57298
- HAANSI_TOKEN API token (or use \`haansi init\` to save it)
57299
- HAANSI_API_URL API base URL (default: https://api.haansi.co)
57300
- CLAUDE_PROJECT_PATH Collect from a specific project path only
57301
- CLAUDE_COLLECT_SCHEDULE Cron expression for daemon (default: */30 * * * *)
57440
+ HAANSI_TOKEN API token (or use \`haansi init\` to save it)
57441
+ HAANSI_API_URL API base URL (default: https://api.haansi.co)
57442
+ CLAUDE_PROJECT_PATH Collect from a specific project path only
57443
+ CLAUDE_COLLECT_SCHEDULE Cron expression for daemon (default: */30 * * * *)
57302
57444
  `);
57303
57445
  }
57304
57446
  run2().catch((err) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "haansi",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "Haansi CLI - Session collector and MCP server for Claude Code",
5
5
  "bin": {
6
6
  "haansi": "./dist/haansi.js"