haansi 0.1.0 → 0.1.1
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 +174 -8
- package/package.json +11 -4
package/dist/haansi.js
CHANGED
|
@@ -97,7 +97,7 @@ var init_init = __esm({
|
|
|
97
97
|
import_node_fs = require("node:fs");
|
|
98
98
|
import_node_path = require("node:path");
|
|
99
99
|
import_node_os = require("node:os");
|
|
100
|
-
DEFAULT_API_URL = "https://api.haansi.
|
|
100
|
+
DEFAULT_API_URL = "https://api.haansi.co";
|
|
101
101
|
HAANSI_DIR = (0, import_node_path.join)((0, import_node_os.homedir)(), ".haansi");
|
|
102
102
|
CREDENTIALS_FILE = (0, import_node_path.join)(HAANSI_DIR, "credentials.json");
|
|
103
103
|
}
|
|
@@ -1104,7 +1104,7 @@ var init_collector = __esm({
|
|
|
1104
1104
|
init_logger();
|
|
1105
1105
|
(0, import_dotenv2.config)({ path: (0, import_path3.resolve)(__dirname, "../../../.env") });
|
|
1106
1106
|
logger3 = createLogger("claude-collector");
|
|
1107
|
-
DEFAULT_API_URL2 = "https://api.haansi.
|
|
1107
|
+
DEFAULT_API_URL2 = "https://api.haansi.co";
|
|
1108
1108
|
CREDENTIALS_FILE2 = (0, import_path3.join)((0, import_os3.homedir)(), ".haansi", "credentials.json");
|
|
1109
1109
|
EDGE_SCRUB_PATTERNS = [
|
|
1110
1110
|
{
|
|
@@ -30355,8 +30355,8 @@ var require_dist = __commonJS({
|
|
|
30355
30355
|
return ajv;
|
|
30356
30356
|
}
|
|
30357
30357
|
const [formats, exportName] = opts.mode === "fast" ? [formats_1.fastFormats, fastName] : [formats_1.fullFormats, fullName];
|
|
30358
|
-
const
|
|
30359
|
-
addFormats(ajv,
|
|
30358
|
+
const list2 = opts.formats || formats_1.formatNames;
|
|
30359
|
+
addFormats(ajv, list2, formats, exportName);
|
|
30360
30360
|
if (opts.keywords)
|
|
30361
30361
|
(0, limit_1.default)(ajv);
|
|
30362
30362
|
return ajv;
|
|
@@ -30368,11 +30368,11 @@ var require_dist = __commonJS({
|
|
|
30368
30368
|
throw new Error(`Unknown format "${name}"`);
|
|
30369
30369
|
return f;
|
|
30370
30370
|
};
|
|
30371
|
-
function addFormats(ajv,
|
|
30371
|
+
function addFormats(ajv, list2, fs, exportName) {
|
|
30372
30372
|
var _a2;
|
|
30373
30373
|
var _b;
|
|
30374
30374
|
(_a2 = (_b = ajv.opts.code).formats) !== null && _a2 !== void 0 ? _a2 : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
|
|
30375
|
-
for (const f of
|
|
30375
|
+
for (const f of list2)
|
|
30376
30376
|
ajv.addFormat(f, fs[f]);
|
|
30377
30377
|
}
|
|
30378
30378
|
module2.exports = exports2 = formatsPlugin;
|
|
@@ -32027,7 +32027,7 @@ var init_mcp_server2 = __esm({
|
|
|
32027
32027
|
init_stdio2();
|
|
32028
32028
|
init_types2();
|
|
32029
32029
|
(0, import_dotenv4.config)({ path: (0, import_path5.resolve)(__dirname, "../../../.env") });
|
|
32030
|
-
DEFAULT_API_URL3 = "https://api.haansi.
|
|
32030
|
+
DEFAULT_API_URL3 = "https://api.haansi.co";
|
|
32031
32031
|
CREDENTIALS_FILE3 = (0, import_path5.join)((0, import_os4.homedir)(), ".haansi", "credentials.json");
|
|
32032
32032
|
API_URL = process.env.HAANSI_API_URL ?? DEFAULT_API_URL3;
|
|
32033
32033
|
TOKEN = resolveToken2();
|
|
@@ -32175,6 +32175,151 @@ var init_setup_mcp = __esm({
|
|
|
32175
32175
|
}
|
|
32176
32176
|
});
|
|
32177
32177
|
|
|
32178
|
+
// src/commands/setup-daemon.ts
|
|
32179
|
+
var setup_daemon_exports = {};
|
|
32180
|
+
__export(setup_daemon_exports, {
|
|
32181
|
+
setupDaemon: () => setupDaemon
|
|
32182
|
+
});
|
|
32183
|
+
function findHaansiBin() {
|
|
32184
|
+
try {
|
|
32185
|
+
return (0, import_node_child_process.execSync)("which haansi", { encoding: "utf-8" }).trim();
|
|
32186
|
+
} catch {
|
|
32187
|
+
throw new Error("Could not find haansi in PATH. Make sure it is installed globally (npm install -g haansi).");
|
|
32188
|
+
}
|
|
32189
|
+
}
|
|
32190
|
+
function buildPlist(haansiPath) {
|
|
32191
|
+
const binDir = haansiPath.replace(/\/[^/]+$/, "");
|
|
32192
|
+
const path = `${binDir}:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin`;
|
|
32193
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
32194
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
32195
|
+
<plist version="1.0">
|
|
32196
|
+
<dict>
|
|
32197
|
+
<key>Label</key>
|
|
32198
|
+
<string>${PLIST_LABEL}</string>
|
|
32199
|
+
<key>ProgramArguments</key>
|
|
32200
|
+
<array>
|
|
32201
|
+
<string>${haansiPath}</string>
|
|
32202
|
+
<string>daemon</string>
|
|
32203
|
+
</array>
|
|
32204
|
+
<key>EnvironmentVariables</key>
|
|
32205
|
+
<dict>
|
|
32206
|
+
<key>PATH</key>
|
|
32207
|
+
<string>${path}</string>
|
|
32208
|
+
</dict>
|
|
32209
|
+
<key>RunAtLoad</key>
|
|
32210
|
+
<true/>
|
|
32211
|
+
<key>KeepAlive</key>
|
|
32212
|
+
<true/>
|
|
32213
|
+
<key>StandardOutPath</key>
|
|
32214
|
+
<string>${LOG_FILE}</string>
|
|
32215
|
+
<key>StandardErrorPath</key>
|
|
32216
|
+
<string>${LOG_FILE}</string>
|
|
32217
|
+
</dict>
|
|
32218
|
+
</plist>`;
|
|
32219
|
+
}
|
|
32220
|
+
async function setupDaemon(uninstall) {
|
|
32221
|
+
if (uninstall) {
|
|
32222
|
+
if (!(0, import_node_fs3.existsSync)(PLIST_PATH)) {
|
|
32223
|
+
console.log("Daemon is not installed.");
|
|
32224
|
+
return;
|
|
32225
|
+
}
|
|
32226
|
+
try {
|
|
32227
|
+
(0, import_node_child_process.execSync)(`launchctl unload "${PLIST_PATH}"`, { stdio: "pipe" });
|
|
32228
|
+
} catch {
|
|
32229
|
+
}
|
|
32230
|
+
(0, import_node_fs3.unlinkSync)(PLIST_PATH);
|
|
32231
|
+
console.log("Daemon stopped and removed.");
|
|
32232
|
+
return;
|
|
32233
|
+
}
|
|
32234
|
+
const haansiPath = findHaansiBin();
|
|
32235
|
+
(0, import_node_fs3.mkdirSync)((0, import_node_path3.join)((0, import_node_os3.homedir)(), ".haansi"), { recursive: true });
|
|
32236
|
+
(0, import_node_fs3.writeFileSync)(PLIST_PATH, buildPlist(haansiPath), "utf-8");
|
|
32237
|
+
try {
|
|
32238
|
+
(0, import_node_child_process.execSync)(`launchctl unload "${PLIST_PATH}"`, { stdio: "pipe" });
|
|
32239
|
+
} catch {
|
|
32240
|
+
}
|
|
32241
|
+
(0, import_node_child_process.execSync)(`launchctl load "${PLIST_PATH}"`, { stdio: "inherit" });
|
|
32242
|
+
console.log("Daemon installed and started.");
|
|
32243
|
+
console.log(`Plist : ${PLIST_PATH}`);
|
|
32244
|
+
console.log(`Logs : ${LOG_FILE}`);
|
|
32245
|
+
console.log(`
|
|
32246
|
+
The daemon will start automatically on every login.`);
|
|
32247
|
+
console.log(`To uninstall: haansi setup-daemon --uninstall`);
|
|
32248
|
+
}
|
|
32249
|
+
var import_node_child_process, import_node_fs3, import_node_path3, import_node_os3, PLIST_LABEL, PLIST_PATH, LOG_FILE;
|
|
32250
|
+
var init_setup_daemon = __esm({
|
|
32251
|
+
"src/commands/setup-daemon.ts"() {
|
|
32252
|
+
"use strict";
|
|
32253
|
+
import_node_child_process = require("node:child_process");
|
|
32254
|
+
import_node_fs3 = require("node:fs");
|
|
32255
|
+
import_node_path3 = require("node:path");
|
|
32256
|
+
import_node_os3 = require("node:os");
|
|
32257
|
+
PLIST_LABEL = "co.haansi.daemon";
|
|
32258
|
+
PLIST_PATH = (0, import_node_path3.join)((0, import_node_os3.homedir)(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
|
|
32259
|
+
LOG_FILE = (0, import_node_path3.join)((0, import_node_os3.homedir)(), ".haansi", "daemon.log");
|
|
32260
|
+
}
|
|
32261
|
+
});
|
|
32262
|
+
|
|
32263
|
+
// src/commands/list.ts
|
|
32264
|
+
var list_exports = {};
|
|
32265
|
+
__export(list_exports, {
|
|
32266
|
+
list: () => list
|
|
32267
|
+
});
|
|
32268
|
+
function resolveToken3() {
|
|
32269
|
+
if (process.env.HAANSI_TOKEN) return process.env.HAANSI_TOKEN;
|
|
32270
|
+
if ((0, import_node_fs4.existsSync)(CREDENTIALS_FILE4)) {
|
|
32271
|
+
try {
|
|
32272
|
+
const creds = JSON.parse((0, import_node_fs4.readFileSync)(CREDENTIALS_FILE4, "utf-8"));
|
|
32273
|
+
if (creds.token) return creds.token;
|
|
32274
|
+
} catch {
|
|
32275
|
+
}
|
|
32276
|
+
}
|
|
32277
|
+
throw new Error("No token found. Run `haansi init` first.");
|
|
32278
|
+
}
|
|
32279
|
+
async function apiGet2(path, token, apiUrl) {
|
|
32280
|
+
const response = await fetch(`${apiUrl}/api/v1${path}`, {
|
|
32281
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
32282
|
+
});
|
|
32283
|
+
if (!response.ok) {
|
|
32284
|
+
const body = await response.text().catch(() => "");
|
|
32285
|
+
throw new Error(`API error ${response.status}: ${body.slice(0, 200)}`);
|
|
32286
|
+
}
|
|
32287
|
+
return response.json();
|
|
32288
|
+
}
|
|
32289
|
+
async function list(options) {
|
|
32290
|
+
const apiUrl = process.env.HAANSI_API_URL ?? DEFAULT_API_URL4;
|
|
32291
|
+
const token = resolveToken3();
|
|
32292
|
+
let data;
|
|
32293
|
+
if (options.search) {
|
|
32294
|
+
data = await apiGet2(
|
|
32295
|
+
`/sessions/search?q=${encodeURIComponent(options.search)}&top_k=${options.limit}`,
|
|
32296
|
+
token,
|
|
32297
|
+
apiUrl
|
|
32298
|
+
);
|
|
32299
|
+
} else {
|
|
32300
|
+
data = await apiGet2(`/sessions/recent?limit=${options.limit}`, token, apiUrl);
|
|
32301
|
+
}
|
|
32302
|
+
if (!data.results || data.results.length === 0) {
|
|
32303
|
+
console.log("No solutions found. Run `haansi collect` to upload sessions.");
|
|
32304
|
+
return;
|
|
32305
|
+
}
|
|
32306
|
+
const separator = "\n" + "\u2500".repeat(60) + "\n";
|
|
32307
|
+
console.log(data.results.join(separator));
|
|
32308
|
+
console.log(`
|
|
32309
|
+
${data.results.length} result(s)`);
|
|
32310
|
+
}
|
|
32311
|
+
var import_node_fs4, import_node_path4, import_node_os4, DEFAULT_API_URL4, CREDENTIALS_FILE4;
|
|
32312
|
+
var init_list = __esm({
|
|
32313
|
+
"src/commands/list.ts"() {
|
|
32314
|
+
"use strict";
|
|
32315
|
+
import_node_fs4 = require("node:fs");
|
|
32316
|
+
import_node_path4 = require("node:path");
|
|
32317
|
+
import_node_os4 = require("node:os");
|
|
32318
|
+
DEFAULT_API_URL4 = "https://api.haansi.co";
|
|
32319
|
+
CREDENTIALS_FILE4 = (0, import_node_path4.join)((0, import_node_os4.homedir)(), ".haansi", "credentials.json");
|
|
32320
|
+
}
|
|
32321
|
+
});
|
|
32322
|
+
|
|
32178
32323
|
// src/index.ts
|
|
32179
32324
|
var command = process.argv[2];
|
|
32180
32325
|
async function run2() {
|
|
@@ -32210,6 +32355,21 @@ Collector done: ${uploaded} uploaded, ${skipped} unchanged, ${errors} errors`);
|
|
|
32210
32355
|
await setupMcp2();
|
|
32211
32356
|
break;
|
|
32212
32357
|
}
|
|
32358
|
+
case "setup-daemon": {
|
|
32359
|
+
const { setupDaemon: setupDaemon2 } = await Promise.resolve().then(() => (init_setup_daemon(), setup_daemon_exports));
|
|
32360
|
+
const uninstall = process.argv.includes("--uninstall");
|
|
32361
|
+
await setupDaemon2(uninstall);
|
|
32362
|
+
break;
|
|
32363
|
+
}
|
|
32364
|
+
case "list": {
|
|
32365
|
+
const { list: list2 } = await Promise.resolve().then(() => (init_list(), list_exports));
|
|
32366
|
+
const searchIdx = process.argv.indexOf("--search");
|
|
32367
|
+
const search = searchIdx !== -1 ? process.argv[searchIdx + 1] : void 0;
|
|
32368
|
+
const limitIdx = process.argv.indexOf("--limit");
|
|
32369
|
+
const limit = limitIdx !== -1 ? parseInt(process.argv[limitIdx + 1], 10) : 10;
|
|
32370
|
+
await list2({ search, limit });
|
|
32371
|
+
break;
|
|
32372
|
+
}
|
|
32213
32373
|
case "help":
|
|
32214
32374
|
default: {
|
|
32215
32375
|
printUsage();
|
|
@@ -32231,8 +32391,14 @@ Commands:
|
|
|
32231
32391
|
daemon Run the collector on a schedule (every 30 min)
|
|
32232
32392
|
mcp-server Start the Haansi MCP server (used by Claude Code)
|
|
32233
32393
|
setup-mcp Add haansi-solutions MCP entry to ~/.claude.json
|
|
32394
|
+
list List or search mined solutions
|
|
32395
|
+
setup-daemon Install launchd service to auto-start daemon on login (macOS)
|
|
32234
32396
|
help Show this help message
|
|
32235
32397
|
|
|
32398
|
+
Options for list:
|
|
32399
|
+
--search <query> Semantic search instead of listing recent
|
|
32400
|
+
--limit <n> Number of results (default: 10)
|
|
32401
|
+
|
|
32236
32402
|
Options for collect:
|
|
32237
32403
|
--force-all Re-upload all sessions, not just new ones
|
|
32238
32404
|
--dry-run Scan without uploading
|
|
@@ -32240,7 +32406,7 @@ Options for collect:
|
|
|
32240
32406
|
|
|
32241
32407
|
Environment variables:
|
|
32242
32408
|
HAANSI_TOKEN API token (or use \`haansi init\` to save it)
|
|
32243
|
-
HAANSI_API_URL API base URL (default: https://api.haansi.
|
|
32409
|
+
HAANSI_API_URL API base URL (default: https://api.haansi.co)
|
|
32244
32410
|
CLAUDE_PROJECT_PATH Collect from a specific project path only
|
|
32245
32411
|
CLAUDE_COLLECT_SCHEDULE Cron expression for daemon (default: */30 * * * *)
|
|
32246
32412
|
`);
|
package/package.json
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "haansi",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Haansi CLI - Session collector and MCP server for Claude Code",
|
|
5
|
-
"bin": {
|
|
6
|
-
|
|
5
|
+
"bin": {
|
|
6
|
+
"haansi": "./dist/haansi.js"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"dist/",
|
|
10
|
+
"README.md"
|
|
11
|
+
],
|
|
7
12
|
"scripts": {
|
|
8
13
|
"build": "node build.mjs",
|
|
9
14
|
"prepublishOnly": "npm run build"
|
|
@@ -13,5 +18,7 @@
|
|
|
13
18
|
"typescript": "^5.7.2",
|
|
14
19
|
"@types/node": "^22.10.1"
|
|
15
20
|
},
|
|
16
|
-
"engines": {
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=18.0.0"
|
|
23
|
+
}
|
|
17
24
|
}
|