@hiveai/cli 0.9.6 → 0.9.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.
- package/dist/index.js +366 -90
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { Command as
|
|
4
|
+
import { Command as Command48 } from "commander";
|
|
5
5
|
|
|
6
6
|
// src/commands/briefing.ts
|
|
7
7
|
import { existsSync } from "fs";
|
|
@@ -843,7 +843,7 @@ async function scanDirs(root, maxDepth = 2) {
|
|
|
843
843
|
if (depth > maxDepth) return;
|
|
844
844
|
let entries;
|
|
845
845
|
try {
|
|
846
|
-
entries = await readdir(dir, { withFileTypes: true });
|
|
846
|
+
entries = await readdir(dir, { withFileTypes: true, encoding: "utf8" });
|
|
847
847
|
} catch {
|
|
848
848
|
return;
|
|
849
849
|
}
|
|
@@ -2171,6 +2171,16 @@ function registerInit(program2) {
|
|
|
2171
2171
|
} else {
|
|
2172
2172
|
ui.warn("Git hooks not installed (not a git repo or no .git/ found) \u2014 run `haive install-hooks` manually");
|
|
2173
2173
|
}
|
|
2174
|
+
const claudeHookResult = spawnSync(
|
|
2175
|
+
process.execPath,
|
|
2176
|
+
[haiveBin, "install-hooks", "claude", "--scope", "project", "--dir", root],
|
|
2177
|
+
{ encoding: "utf8" }
|
|
2178
|
+
);
|
|
2179
|
+
if (claudeHookResult.status === 0) {
|
|
2180
|
+
ui.success("Claude Code enforcement hooks installed (.claude/settings.local.json)");
|
|
2181
|
+
} else {
|
|
2182
|
+
ui.warn("Claude Code hooks not installed \u2014 run `haive install-hooks claude --scope project` manually");
|
|
2183
|
+
}
|
|
2174
2184
|
try {
|
|
2175
2185
|
ui.info("Building code-map\u2026");
|
|
2176
2186
|
const map = await buildCodeMap2(root);
|
|
@@ -2342,7 +2352,7 @@ import { findProjectRoot as findProjectRoot6 } from "@hiveai/core";
|
|
|
2342
2352
|
import { existsSync as existsSync7 } from "fs";
|
|
2343
2353
|
import { mkdir as mkdir4, readFile as readFile5, writeFile as writeFile4 } from "fs/promises";
|
|
2344
2354
|
import path8 from "path";
|
|
2345
|
-
var HAIVE_HOOK_TAG = "haive-
|
|
2355
|
+
var HAIVE_HOOK_TAG = "haive-enforcement";
|
|
2346
2356
|
var POST_TOOL_USE_GROUP = {
|
|
2347
2357
|
matcher: "Edit|Write|Bash",
|
|
2348
2358
|
hooks: [
|
|
@@ -2353,6 +2363,25 @@ var POST_TOOL_USE_GROUP = {
|
|
|
2353
2363
|
}
|
|
2354
2364
|
]
|
|
2355
2365
|
};
|
|
2366
|
+
var PRE_TOOL_USE_GROUP = {
|
|
2367
|
+
matcher: "Edit|Write|MultiEdit|NotebookEdit|Bash",
|
|
2368
|
+
hooks: [
|
|
2369
|
+
{
|
|
2370
|
+
type: "command",
|
|
2371
|
+
command: "haive enforce pre-tool-use",
|
|
2372
|
+
haive_tag: HAIVE_HOOK_TAG
|
|
2373
|
+
}
|
|
2374
|
+
]
|
|
2375
|
+
};
|
|
2376
|
+
var SESSION_START_GROUP = {
|
|
2377
|
+
hooks: [
|
|
2378
|
+
{
|
|
2379
|
+
type: "command",
|
|
2380
|
+
command: "haive enforce session-start",
|
|
2381
|
+
haive_tag: HAIVE_HOOK_TAG
|
|
2382
|
+
}
|
|
2383
|
+
]
|
|
2384
|
+
};
|
|
2356
2385
|
var SESSION_END_GROUP = {
|
|
2357
2386
|
hooks: [
|
|
2358
2387
|
{
|
|
@@ -2370,6 +2399,14 @@ function dropHaiveGroups(groups) {
|
|
|
2370
2399
|
function patchClaudeSettings(input) {
|
|
2371
2400
|
const settings = input ? { ...input } : {};
|
|
2372
2401
|
const hooks = settings.hooks ? { ...settings.hooks } : {};
|
|
2402
|
+
hooks.SessionStart = [
|
|
2403
|
+
...dropHaiveGroups(hooks.SessionStart ?? []),
|
|
2404
|
+
SESSION_START_GROUP
|
|
2405
|
+
];
|
|
2406
|
+
hooks.PreToolUse = [
|
|
2407
|
+
...dropHaiveGroups(hooks.PreToolUse ?? []),
|
|
2408
|
+
PRE_TOOL_USE_GROUP
|
|
2409
|
+
];
|
|
2373
2410
|
hooks.PostToolUse = [
|
|
2374
2411
|
...dropHaiveGroups(hooks.PostToolUse ?? []),
|
|
2375
2412
|
POST_TOOL_USE_GROUP
|
|
@@ -2523,7 +2560,7 @@ async function installClaudeHooks(opts) {
|
|
|
2523
2560
|
try {
|
|
2524
2561
|
const result = await installClaudeHooksAtPath(settingsPath);
|
|
2525
2562
|
if (result.created) {
|
|
2526
|
-
ui.success(`Created ${result.settingsPath} with hAIve
|
|
2563
|
+
ui.success(`Created ${result.settingsPath} with hAIve enforcement hooks`);
|
|
2527
2564
|
} else {
|
|
2528
2565
|
ui.success(`Patched ${result.settingsPath} (existing user hooks preserved)`);
|
|
2529
2566
|
}
|
|
@@ -2532,8 +2569,9 @@ async function installClaudeHooks(opts) {
|
|
|
2532
2569
|
process.exitCode = 1;
|
|
2533
2570
|
return;
|
|
2534
2571
|
}
|
|
2535
|
-
ui.info("
|
|
2536
|
-
ui.info("
|
|
2572
|
+
ui.info("SessionStart hook: `haive enforce session-start` injects briefing context");
|
|
2573
|
+
ui.info("PreToolUse hook: blocks Edit/Write/dangerous Bash until briefing is loaded");
|
|
2574
|
+
ui.info("PostToolUse hook: `haive observe` captures Edit/Write/Bash activity");
|
|
2537
2575
|
ui.info("SessionEnd hook: `haive session end --auto --quiet` distills observations");
|
|
2538
2576
|
ui.info(" into a session_recap memory at session close");
|
|
2539
2577
|
ui.info("Restart Claude Code (or open a new conversation) for the hooks to take effect.");
|
|
@@ -2541,7 +2579,7 @@ async function installClaudeHooks(opts) {
|
|
|
2541
2579
|
}
|
|
2542
2580
|
function registerInstallHooks(program2) {
|
|
2543
2581
|
program2.command("install-hooks [target]").description(
|
|
2544
|
-
"Install hAIve hooks. Targets:\n\n git (default) post-merge / post-rewrite / pre-push for haive sync + precommit\n claude PostToolUse + SessionEnd hooks
|
|
2582
|
+
"Install hAIve hooks. Targets:\n\n git (default) post-merge / post-rewrite / pre-push for haive sync + precommit\n claude SessionStart + PreToolUse + PostToolUse + SessionEnd hooks\n for briefing injection, pre-edit blocking, and capture (Claude Code only)\n\n Examples:\n haive install-hooks # git hooks (legacy default)\n haive install-hooks git\n haive install-hooks claude\n haive install-hooks claude --scope project\n haive install-hooks claude --uninstall\n"
|
|
2545
2583
|
).option("-d, --dir <dir>", "project root").option("--force", "overwrite existing hooks (git target only)").option("--scope <scope>", "claude target: 'user' (~/.claude) or 'project' (.claude/)", "user").option("--uninstall", "remove previously installed hAIve hooks (claude target only)").option("--settings <path>", "explicit path to settings.json (claude target only)").action(async (target, opts) => {
|
|
2546
2584
|
const t = (target ?? "git").toLowerCase();
|
|
2547
2585
|
if (t === "git") {
|
|
@@ -2926,6 +2964,7 @@ import { z as z35 } from "zod";
|
|
|
2926
2964
|
import { z as z36 } from "zod";
|
|
2927
2965
|
import { z as z37 } from "zod";
|
|
2928
2966
|
import { z as z38 } from "zod";
|
|
2967
|
+
import { loadConfigSync } from "@hiveai/core";
|
|
2929
2968
|
function createContext(options = {}) {
|
|
2930
2969
|
const env = options.env ?? process.env;
|
|
2931
2970
|
const cwd = options.cwd ?? process.cwd();
|
|
@@ -4622,6 +4661,7 @@ var CodeMapInputSchema = {
|
|
|
4622
4661
|
"Approximate token budget for the response. When the matching set exceeds it, files are ranked by export density (exports per LOC) and the highest-signal ones are kept first. Omit to disable budgeting (legacy behavior)."
|
|
4623
4662
|
)
|
|
4624
4663
|
};
|
|
4664
|
+
var CodeMapInputZod = z18.object(CodeMapInputSchema);
|
|
4625
4665
|
async function codeMapTool(input, ctx) {
|
|
4626
4666
|
const map = await loadCodeMap22(ctx.paths);
|
|
4627
4667
|
if (!map) {
|
|
@@ -6029,7 +6069,7 @@ When done, respond with: "Imported N memories: [list of IDs]" or "Nothing action
|
|
|
6029
6069
|
};
|
|
6030
6070
|
}
|
|
6031
6071
|
var SERVER_NAME = "haive";
|
|
6032
|
-
var SERVER_VERSION = "0.9.
|
|
6072
|
+
var SERVER_VERSION = "0.9.8";
|
|
6033
6073
|
function jsonResult(data) {
|
|
6034
6074
|
return {
|
|
6035
6075
|
content: [
|
|
@@ -6040,15 +6080,70 @@ function jsonResult(data) {
|
|
|
6040
6080
|
]
|
|
6041
6081
|
};
|
|
6042
6082
|
}
|
|
6083
|
+
var ENFORCEMENT_PROFILE_TOOLS = /* @__PURE__ */ new Set([
|
|
6084
|
+
"get_briefing",
|
|
6085
|
+
"mem_save",
|
|
6086
|
+
"mem_tried",
|
|
6087
|
+
"mem_search",
|
|
6088
|
+
"mem_get",
|
|
6089
|
+
"mem_update",
|
|
6090
|
+
"mem_verify",
|
|
6091
|
+
"mem_relevant_to",
|
|
6092
|
+
"code_map",
|
|
6093
|
+
"pre_commit_check"
|
|
6094
|
+
]);
|
|
6095
|
+
var BRIEFING_TOOLS = /* @__PURE__ */ new Set(["get_briefing", "mem_relevant_to"]);
|
|
6096
|
+
var MUTATING_TOOLS = /* @__PURE__ */ new Set([
|
|
6097
|
+
"mem_save",
|
|
6098
|
+
"mem_tried",
|
|
6099
|
+
"mem_observe",
|
|
6100
|
+
"mem_session_end",
|
|
6101
|
+
"bootstrap_project_save",
|
|
6102
|
+
"mem_update",
|
|
6103
|
+
"mem_approve",
|
|
6104
|
+
"mem_reject",
|
|
6105
|
+
"mem_delete",
|
|
6106
|
+
"runtime_journal_append",
|
|
6107
|
+
"pattern_detect"
|
|
6108
|
+
]);
|
|
6043
6109
|
function createHaiveServer(options = {}) {
|
|
6044
6110
|
const context = createContext(options);
|
|
6111
|
+
const config = loadConfigSync(context.paths);
|
|
6112
|
+
const toolProfile = options.env?.HAIVE_TOOL_PROFILE ?? config.enforcement?.toolProfile ?? "enforcement";
|
|
6113
|
+
const requireBriefingFirst = options.env?.HAIVE_REQUIRE_BRIEFING_FIRST === "0" ? false : config.enforcement?.requireBriefingFirst ?? true;
|
|
6114
|
+
let briefingLoaded = false;
|
|
6045
6115
|
const tracker = new SessionTracker(context);
|
|
6046
6116
|
void tracker.init();
|
|
6047
6117
|
const server = new McpServer(
|
|
6048
6118
|
{ name: SERVER_NAME, version: SERVER_VERSION },
|
|
6049
6119
|
{ capabilities: { tools: {}, prompts: {} } }
|
|
6050
6120
|
);
|
|
6051
|
-
|
|
6121
|
+
const shouldRegisterTool = (name) => toolProfile === "full" || ENFORCEMENT_PROFILE_TOOLS.has(name);
|
|
6122
|
+
const registerTool = (name, description, schema, handler) => {
|
|
6123
|
+
if (!shouldRegisterTool(name)) return;
|
|
6124
|
+
const tool = server.tool.bind(server);
|
|
6125
|
+
tool(
|
|
6126
|
+
name,
|
|
6127
|
+
description,
|
|
6128
|
+
schema,
|
|
6129
|
+
async (input) => {
|
|
6130
|
+
if (BRIEFING_TOOLS.has(name)) {
|
|
6131
|
+
briefingLoaded = true;
|
|
6132
|
+
return await handler(input);
|
|
6133
|
+
}
|
|
6134
|
+
if (requireBriefingFirst && MUTATING_TOOLS.has(name) && !briefingLoaded) {
|
|
6135
|
+
return jsonResult({
|
|
6136
|
+
error: "haive_briefing_required",
|
|
6137
|
+
message: "This hAIve project requires get_briefing or mem_relevant_to before state-changing hAIve tools. Call get_briefing({ task: '...' }) first.",
|
|
6138
|
+
tool: name
|
|
6139
|
+
});
|
|
6140
|
+
}
|
|
6141
|
+
return await handler(input);
|
|
6142
|
+
}
|
|
6143
|
+
);
|
|
6144
|
+
};
|
|
6145
|
+
const shouldRegisterPrompt = (name) => toolProfile === "full" || name === "bootstrap_project" || name === "post_task";
|
|
6146
|
+
registerTool(
|
|
6052
6147
|
"mem_save",
|
|
6053
6148
|
[
|
|
6054
6149
|
"Save a piece of knowledge as a persistent memory that survives across AI sessions.",
|
|
@@ -6080,7 +6175,7 @@ function createHaiveServer(options = {}) {
|
|
|
6080
6175
|
return jsonResult(await memSave(input, context));
|
|
6081
6176
|
}
|
|
6082
6177
|
);
|
|
6083
|
-
|
|
6178
|
+
registerTool(
|
|
6084
6179
|
"mem_suggest_topic",
|
|
6085
6180
|
[
|
|
6086
6181
|
"Propose a stable `topic` key (topic-upsert) from type + short title.",
|
|
@@ -6097,7 +6192,7 @@ function createHaiveServer(options = {}) {
|
|
|
6097
6192
|
MemSuggestTopicInputSchema,
|
|
6098
6193
|
async (input) => jsonResult(await memSuggestTopic(input, context))
|
|
6099
6194
|
);
|
|
6100
|
-
|
|
6195
|
+
registerTool(
|
|
6101
6196
|
"mem_tried",
|
|
6102
6197
|
[
|
|
6103
6198
|
"Record a FAILED approach so future agents don't repeat the same mistake.",
|
|
@@ -6124,7 +6219,7 @@ function createHaiveServer(options = {}) {
|
|
|
6124
6219
|
return jsonResult(await memTried(input, context));
|
|
6125
6220
|
}
|
|
6126
6221
|
);
|
|
6127
|
-
|
|
6222
|
+
registerTool(
|
|
6128
6223
|
"mem_observe",
|
|
6129
6224
|
[
|
|
6130
6225
|
"Capture a code-level discovery made WHILE READING existing code.",
|
|
@@ -6156,7 +6251,7 @@ function createHaiveServer(options = {}) {
|
|
|
6156
6251
|
return jsonResult(await memObserve(input, context));
|
|
6157
6252
|
}
|
|
6158
6253
|
);
|
|
6159
|
-
|
|
6254
|
+
registerTool(
|
|
6160
6255
|
"mem_session_end",
|
|
6161
6256
|
[
|
|
6162
6257
|
"Save an end-of-session recap so the NEXT session starts with fresh context.",
|
|
@@ -6185,7 +6280,7 @@ function createHaiveServer(options = {}) {
|
|
|
6185
6280
|
return jsonResult(await memSessionEnd(input, context));
|
|
6186
6281
|
}
|
|
6187
6282
|
);
|
|
6188
|
-
|
|
6283
|
+
registerTool(
|
|
6189
6284
|
"get_briefing",
|
|
6190
6285
|
[
|
|
6191
6286
|
"\u2B50 DEFAULT-FIRST for coding agents on any repo where `haive init` ran: call this BEFORE",
|
|
@@ -6236,7 +6331,7 @@ function createHaiveServer(options = {}) {
|
|
|
6236
6331
|
return jsonResult(await getBriefing(input, context));
|
|
6237
6332
|
}
|
|
6238
6333
|
);
|
|
6239
|
-
|
|
6334
|
+
registerTool(
|
|
6240
6335
|
"mem_search",
|
|
6241
6336
|
[
|
|
6242
6337
|
"Search memories by keyword or semantic similarity.",
|
|
@@ -6268,7 +6363,7 @@ function createHaiveServer(options = {}) {
|
|
|
6268
6363
|
return jsonResult(await memSearch(input, context));
|
|
6269
6364
|
}
|
|
6270
6365
|
);
|
|
6271
|
-
|
|
6366
|
+
registerTool(
|
|
6272
6367
|
"mem_timeline",
|
|
6273
6368
|
[
|
|
6274
6369
|
"Chronological view of related memories: by shared frontmatter.topic OR expanded from a seed id",
|
|
@@ -6284,7 +6379,7 @@ function createHaiveServer(options = {}) {
|
|
|
6284
6379
|
MemTimelineInputSchema,
|
|
6285
6380
|
async (input) => jsonResult(await memTimeline(input, context))
|
|
6286
6381
|
);
|
|
6287
|
-
|
|
6382
|
+
registerTool(
|
|
6288
6383
|
"mem_for_files",
|
|
6289
6384
|
[
|
|
6290
6385
|
"Surface memories relevant to the files you are currently editing.",
|
|
@@ -6308,7 +6403,7 @@ function createHaiveServer(options = {}) {
|
|
|
6308
6403
|
MemForFilesInputSchema,
|
|
6309
6404
|
async (input) => jsonResult(await memForFiles(input, context))
|
|
6310
6405
|
);
|
|
6311
|
-
|
|
6406
|
+
registerTool(
|
|
6312
6407
|
"mem_get",
|
|
6313
6408
|
[
|
|
6314
6409
|
"Fetch a single memory by its full id with all details.",
|
|
@@ -6324,7 +6419,7 @@ function createHaiveServer(options = {}) {
|
|
|
6324
6419
|
MemGetInputSchema,
|
|
6325
6420
|
async (input) => jsonResult(await memGet(input, context))
|
|
6326
6421
|
);
|
|
6327
|
-
|
|
6422
|
+
registerTool(
|
|
6328
6423
|
"mem_list",
|
|
6329
6424
|
[
|
|
6330
6425
|
"List memories with optional filters. Use for browsing, not for task onboarding.",
|
|
@@ -6344,7 +6439,7 @@ function createHaiveServer(options = {}) {
|
|
|
6344
6439
|
MemListInputSchema,
|
|
6345
6440
|
async (input) => jsonResult(await memList(input, context))
|
|
6346
6441
|
);
|
|
6347
|
-
|
|
6442
|
+
registerTool(
|
|
6348
6443
|
"get_project_context",
|
|
6349
6444
|
[
|
|
6350
6445
|
"Read .ai/project-context.md (and optionally a module context) directly.",
|
|
@@ -6362,7 +6457,7 @@ function createHaiveServer(options = {}) {
|
|
|
6362
6457
|
GetProjectContextInputSchema,
|
|
6363
6458
|
async (input) => jsonResult(await getProjectContext(input, context))
|
|
6364
6459
|
);
|
|
6365
|
-
|
|
6460
|
+
registerTool(
|
|
6366
6461
|
"bootstrap_project_save",
|
|
6367
6462
|
[
|
|
6368
6463
|
"Persist the project context document (.ai/project-context.md) or a module",
|
|
@@ -6380,7 +6475,7 @@ function createHaiveServer(options = {}) {
|
|
|
6380
6475
|
BootstrapProjectSaveInputSchema,
|
|
6381
6476
|
async (input) => jsonResult(await bootstrapProjectSave(input, context))
|
|
6382
6477
|
);
|
|
6383
|
-
|
|
6478
|
+
registerTool(
|
|
6384
6479
|
"code_map",
|
|
6385
6480
|
[
|
|
6386
6481
|
"Look up where symbols (classes, functions, interfaces) are defined in the codebase.",
|
|
@@ -6401,7 +6496,7 @@ function createHaiveServer(options = {}) {
|
|
|
6401
6496
|
CodeMapInputSchema,
|
|
6402
6497
|
async (input) => jsonResult(await codeMapTool(input, context))
|
|
6403
6498
|
);
|
|
6404
|
-
|
|
6499
|
+
registerTool(
|
|
6405
6500
|
"mem_resolve_project",
|
|
6406
6501
|
[
|
|
6407
6502
|
"Diagnostics: resolve which project root hAIve is using (never throws).",
|
|
@@ -6417,7 +6512,7 @@ function createHaiveServer(options = {}) {
|
|
|
6417
6512
|
MemResolveProjectInputSchema,
|
|
6418
6513
|
async (input) => jsonResult(await memResolveProject(input, context))
|
|
6419
6514
|
);
|
|
6420
|
-
|
|
6515
|
+
registerTool(
|
|
6421
6516
|
"mem_update",
|
|
6422
6517
|
[
|
|
6423
6518
|
"Update the body, tags, or anchor of an existing memory in-place.",
|
|
@@ -6440,7 +6535,7 @@ function createHaiveServer(options = {}) {
|
|
|
6440
6535
|
MemUpdateInputSchema,
|
|
6441
6536
|
async (input) => jsonResult(await memUpdate(input, context))
|
|
6442
6537
|
);
|
|
6443
|
-
|
|
6538
|
+
registerTool(
|
|
6444
6539
|
"mem_verify",
|
|
6445
6540
|
[
|
|
6446
6541
|
"Check whether memory anchor paths and symbols still exist in the current code.",
|
|
@@ -6459,7 +6554,7 @@ function createHaiveServer(options = {}) {
|
|
|
6459
6554
|
MemVerifyInputSchema,
|
|
6460
6555
|
async (input) => jsonResult(await memVerify(input, context))
|
|
6461
6556
|
);
|
|
6462
|
-
|
|
6557
|
+
registerTool(
|
|
6463
6558
|
"mem_approve",
|
|
6464
6559
|
[
|
|
6465
6560
|
"Mark a memory as validated (trusted, approved by a human or the team).",
|
|
@@ -6475,7 +6570,7 @@ function createHaiveServer(options = {}) {
|
|
|
6475
6570
|
MemApproveInputSchema,
|
|
6476
6571
|
async (input) => jsonResult(await memApprove(input, context))
|
|
6477
6572
|
);
|
|
6478
|
-
|
|
6573
|
+
registerTool(
|
|
6479
6574
|
"mem_reject",
|
|
6480
6575
|
[
|
|
6481
6576
|
"Mark a memory as rejected and record a reason.",
|
|
@@ -6493,7 +6588,7 @@ function createHaiveServer(options = {}) {
|
|
|
6493
6588
|
MemRejectInputSchema,
|
|
6494
6589
|
async (input) => jsonResult(await memReject(input, context))
|
|
6495
6590
|
);
|
|
6496
|
-
|
|
6591
|
+
registerTool(
|
|
6497
6592
|
"mem_pending",
|
|
6498
6593
|
[
|
|
6499
6594
|
"List memories in 'proposed' status awaiting review, sorted by read count.",
|
|
@@ -6509,7 +6604,7 @@ function createHaiveServer(options = {}) {
|
|
|
6509
6604
|
MemPendingInputSchema,
|
|
6510
6605
|
async (input) => jsonResult(await memPending(input, context))
|
|
6511
6606
|
);
|
|
6512
|
-
|
|
6607
|
+
registerTool(
|
|
6513
6608
|
"mem_delete",
|
|
6514
6609
|
[
|
|
6515
6610
|
"Permanently delete a memory by id.",
|
|
@@ -6526,7 +6621,7 @@ function createHaiveServer(options = {}) {
|
|
|
6526
6621
|
MemDeleteInputSchema,
|
|
6527
6622
|
async (input) => jsonResult(await memDelete(input, context))
|
|
6528
6623
|
);
|
|
6529
|
-
|
|
6624
|
+
registerTool(
|
|
6530
6625
|
"get_recap",
|
|
6531
6626
|
[
|
|
6532
6627
|
"Return ONLY the most recent session_recap. Cheaper than get_briefing when",
|
|
@@ -6544,7 +6639,7 @@ function createHaiveServer(options = {}) {
|
|
|
6544
6639
|
return jsonResult(await getRecap(input, context));
|
|
6545
6640
|
}
|
|
6546
6641
|
);
|
|
6547
|
-
|
|
6642
|
+
registerTool(
|
|
6548
6643
|
"mem_relevant_to",
|
|
6549
6644
|
[
|
|
6550
6645
|
"One-shot ranked memories for a task \u2014 use instead of get_briefing when",
|
|
@@ -6570,7 +6665,7 @@ function createHaiveServer(options = {}) {
|
|
|
6570
6665
|
return jsonResult(await memRelevantTo(input, context));
|
|
6571
6666
|
}
|
|
6572
6667
|
);
|
|
6573
|
-
|
|
6668
|
+
registerTool(
|
|
6574
6669
|
"code_search",
|
|
6575
6670
|
[
|
|
6576
6671
|
"Semantic search over the codebase \u2014 finds exported symbols (functions, classes,",
|
|
@@ -6593,7 +6688,7 @@ function createHaiveServer(options = {}) {
|
|
|
6593
6688
|
return jsonResult(await codeSearch(input, context));
|
|
6594
6689
|
}
|
|
6595
6690
|
);
|
|
6596
|
-
|
|
6691
|
+
registerTool(
|
|
6597
6692
|
"why_this_file",
|
|
6598
6693
|
[
|
|
6599
6694
|
"One-shot file-context lookup: combines recent git history, memories anchored",
|
|
@@ -6613,7 +6708,7 @@ function createHaiveServer(options = {}) {
|
|
|
6613
6708
|
return jsonResult(await whyThisFile(input, context));
|
|
6614
6709
|
}
|
|
6615
6710
|
);
|
|
6616
|
-
|
|
6711
|
+
registerTool(
|
|
6617
6712
|
"anti_patterns_check",
|
|
6618
6713
|
[
|
|
6619
6714
|
"Scan a diff (or set of paths) against documented attempt/gotcha memories.",
|
|
@@ -6636,7 +6731,7 @@ function createHaiveServer(options = {}) {
|
|
|
6636
6731
|
return jsonResult(await antiPatternsCheck(input, context));
|
|
6637
6732
|
}
|
|
6638
6733
|
);
|
|
6639
|
-
|
|
6734
|
+
registerTool(
|
|
6640
6735
|
"mem_distill",
|
|
6641
6736
|
[
|
|
6642
6737
|
"Cluster recurring observations / failed attempts so a human can collapse",
|
|
@@ -6661,7 +6756,7 @@ function createHaiveServer(options = {}) {
|
|
|
6661
6756
|
return jsonResult(await memDistill(input, context));
|
|
6662
6757
|
}
|
|
6663
6758
|
);
|
|
6664
|
-
|
|
6759
|
+
registerTool(
|
|
6665
6760
|
"why_this_decision",
|
|
6666
6761
|
[
|
|
6667
6762
|
"Trace the genealogy of a memory (especially decision/architecture):",
|
|
@@ -6683,7 +6778,7 @@ function createHaiveServer(options = {}) {
|
|
|
6683
6778
|
return jsonResult(await whyThisDecision(input, context));
|
|
6684
6779
|
}
|
|
6685
6780
|
);
|
|
6686
|
-
|
|
6781
|
+
registerTool(
|
|
6687
6782
|
"mem_conflicts_with",
|
|
6688
6783
|
[
|
|
6689
6784
|
"Detect memories that potentially CONTRADICT a given memory.",
|
|
@@ -6709,7 +6804,7 @@ function createHaiveServer(options = {}) {
|
|
|
6709
6804
|
return jsonResult(await memConflicts(input, context));
|
|
6710
6805
|
}
|
|
6711
6806
|
);
|
|
6712
|
-
|
|
6807
|
+
registerTool(
|
|
6713
6808
|
"mem_conflict_candidates",
|
|
6714
6809
|
[
|
|
6715
6810
|
"Bulk scan for conflict CANDIDATES (not proof):",
|
|
@@ -6730,7 +6825,7 @@ function createHaiveServer(options = {}) {
|
|
|
6730
6825
|
return jsonResult(await memConflictCandidates(input, context));
|
|
6731
6826
|
}
|
|
6732
6827
|
);
|
|
6733
|
-
|
|
6828
|
+
registerTool(
|
|
6734
6829
|
"runtime_journal_append",
|
|
6735
6830
|
[
|
|
6736
6831
|
"Append one line to `.ai/.runtime/session-journal.ndjson` \u2014 machine-local session continuity.",
|
|
@@ -6744,7 +6839,7 @@ function createHaiveServer(options = {}) {
|
|
|
6744
6839
|
RuntimeJournalAppendInputSchema,
|
|
6745
6840
|
async (input) => jsonResult(await runtimeJournalAppend(input, context))
|
|
6746
6841
|
);
|
|
6747
|
-
|
|
6842
|
+
registerTool(
|
|
6748
6843
|
"runtime_journal_tail",
|
|
6749
6844
|
[
|
|
6750
6845
|
"Read the last N entries from the runtime session journal (parsed JSON lines).",
|
|
@@ -6756,7 +6851,7 @@ function createHaiveServer(options = {}) {
|
|
|
6756
6851
|
RuntimeJournalTailInputSchema,
|
|
6757
6852
|
async (input) => jsonResult(await runtimeJournalTail(input, context))
|
|
6758
6853
|
);
|
|
6759
|
-
|
|
6854
|
+
registerTool(
|
|
6760
6855
|
"pre_commit_check",
|
|
6761
6856
|
[
|
|
6762
6857
|
"One-shot 'should I block this commit?' check. Combines three signals:",
|
|
@@ -6781,7 +6876,7 @@ function createHaiveServer(options = {}) {
|
|
|
6781
6876
|
return jsonResult(await preCommitCheck(input, context));
|
|
6782
6877
|
}
|
|
6783
6878
|
);
|
|
6784
|
-
|
|
6879
|
+
registerTool(
|
|
6785
6880
|
"pattern_detect",
|
|
6786
6881
|
[
|
|
6787
6882
|
"Heuristic memory detector \u2014 finds knowledge worth saving WITHOUT calling an LLM.",
|
|
@@ -6812,7 +6907,7 @@ function createHaiveServer(options = {}) {
|
|
|
6812
6907
|
return jsonResult(await patternDetect(input, context));
|
|
6813
6908
|
}
|
|
6814
6909
|
);
|
|
6815
|
-
|
|
6910
|
+
registerTool(
|
|
6816
6911
|
"mem_diff",
|
|
6817
6912
|
[
|
|
6818
6913
|
"Compare two memories side-by-side to decide if they should be merged.",
|
|
@@ -6829,44 +6924,50 @@ function createHaiveServer(options = {}) {
|
|
|
6829
6924
|
MemDiffInputSchema,
|
|
6830
6925
|
async (input) => jsonResult(await memDiff(input, context))
|
|
6831
6926
|
);
|
|
6832
|
-
|
|
6833
|
-
|
|
6834
|
-
|
|
6835
|
-
|
|
6836
|
-
|
|
6837
|
-
|
|
6838
|
-
|
|
6839
|
-
|
|
6840
|
-
|
|
6841
|
-
|
|
6842
|
-
|
|
6843
|
-
|
|
6844
|
-
|
|
6845
|
-
|
|
6846
|
-
|
|
6847
|
-
|
|
6848
|
-
"
|
|
6849
|
-
|
|
6850
|
-
|
|
6851
|
-
|
|
6852
|
-
|
|
6853
|
-
|
|
6854
|
-
|
|
6855
|
-
|
|
6856
|
-
|
|
6857
|
-
|
|
6858
|
-
|
|
6859
|
-
|
|
6860
|
-
|
|
6861
|
-
"
|
|
6862
|
-
|
|
6863
|
-
|
|
6864
|
-
|
|
6865
|
-
|
|
6927
|
+
if (shouldRegisterPrompt("bootstrap_project")) {
|
|
6928
|
+
server.prompt(
|
|
6929
|
+
"bootstrap_project",
|
|
6930
|
+
[
|
|
6931
|
+
"Analyze the project codebase and write .ai/project-context.md \u2014 run once after haive init.",
|
|
6932
|
+
"The AI explores the directory structure, reads key files (package.json, README, config),",
|
|
6933
|
+
"identifies the tech stack, architectural patterns, key modules, and conventions,",
|
|
6934
|
+
"then persists everything via bootstrap_project_save.",
|
|
6935
|
+
"For multi-component projects, run with module param to create .ai/modules/<name>/context.md."
|
|
6936
|
+
].join(" "),
|
|
6937
|
+
BootstrapProjectArgsSchema,
|
|
6938
|
+
(args) => bootstrapProjectPrompt(args, context)
|
|
6939
|
+
);
|
|
6940
|
+
}
|
|
6941
|
+
if (shouldRegisterPrompt("post_task")) {
|
|
6942
|
+
server.prompt(
|
|
6943
|
+
"post_task",
|
|
6944
|
+
[
|
|
6945
|
+
"\u2B50 Post-task reflection \u2014 run at the end of every session to capture what you learned:",
|
|
6946
|
+
"failed approaches (mem_tried), new conventions/decisions/gotchas (mem_save),",
|
|
6947
|
+
"code discoveries (mem_observe), and an end-of-session recap (mem_session_end).",
|
|
6948
|
+
"In autopilot mode a minimal recap saves automatically; calling this produces a richer one."
|
|
6949
|
+
].join(" "),
|
|
6950
|
+
PostTaskArgsSchema,
|
|
6951
|
+
(args) => postTaskPrompt(args, context)
|
|
6952
|
+
);
|
|
6953
|
+
}
|
|
6954
|
+
if (shouldRegisterPrompt("import_docs")) {
|
|
6955
|
+
server.prompt(
|
|
6956
|
+
"import_docs",
|
|
6957
|
+
[
|
|
6958
|
+
"Import knowledge from a document (README, ADR, wiki, API spec) as hAIve memories.",
|
|
6959
|
+
"Pass the full document content; the AI extracts up to 10 actionable memories",
|
|
6960
|
+
"(conventions, decisions, gotchas, architecture) and saves them via mem_save.",
|
|
6961
|
+
"Good candidates: ADRs, onboarding docs, runbooks, team wikis."
|
|
6962
|
+
].join(" "),
|
|
6963
|
+
ImportDocsArgsSchema,
|
|
6964
|
+
(args) => importDocsPrompt(args, context)
|
|
6965
|
+
);
|
|
6966
|
+
}
|
|
6866
6967
|
return { server, context, tracker };
|
|
6867
6968
|
}
|
|
6868
6969
|
async function runHaiveMcpStdio(options) {
|
|
6869
|
-
const { server, context } = createHaiveServer({ root: options.root });
|
|
6970
|
+
const { server, context } = createHaiveServer({ root: options.root, env: process.env });
|
|
6870
6971
|
console.error(
|
|
6871
6972
|
`[haive-mcp] starting server v${SERVER_VERSION} (project root: ${context.paths.root})`
|
|
6872
6973
|
);
|
|
@@ -7287,9 +7388,10 @@ Attends une **confirmation explicite** avant d'agir.
|
|
|
7287
7388
|
}
|
|
7288
7389
|
if (opts.embed) {
|
|
7289
7390
|
try {
|
|
7290
|
-
const
|
|
7391
|
+
const { Embedder, rebuildIndex } = await import("@hiveai/embeddings");
|
|
7291
7392
|
log(ui.dim("embed: rebuilding index\u2026"));
|
|
7292
|
-
const
|
|
7393
|
+
const embedder = await Embedder.create();
|
|
7394
|
+
const { report } = await rebuildIndex(paths, embedder);
|
|
7293
7395
|
log(ui.dim(`embed: index rebuilt (${report.added} added, ${report.updated} updated, ${report.removed} removed)`));
|
|
7294
7396
|
} catch {
|
|
7295
7397
|
ui.warn("--embed: @hiveai/embeddings not available or index build failed. Run `haive embeddings index` manually.");
|
|
@@ -8718,8 +8820,8 @@ function parseChangelog(content) {
|
|
|
8718
8820
|
const sections = content.split(/^#{1,3}\s+/m).slice(1);
|
|
8719
8821
|
for (const section of sections) {
|
|
8720
8822
|
const versionMatch = section.match(/^(?:\[?)([0-9]+\.[0-9]+[.0-9]*)/);
|
|
8721
|
-
|
|
8722
|
-
|
|
8823
|
+
const version = versionMatch?.[1];
|
|
8824
|
+
if (!version) continue;
|
|
8723
8825
|
const entry = {
|
|
8724
8826
|
version,
|
|
8725
8827
|
breaking: [],
|
|
@@ -8730,7 +8832,7 @@ function parseChangelog(content) {
|
|
|
8730
8832
|
};
|
|
8731
8833
|
const subSections = section.split(/^#{2,4}\s+/m);
|
|
8732
8834
|
for (const sub of subSections) {
|
|
8733
|
-
const firstLine = sub.split("\n")[0].toLowerCase().trim();
|
|
8835
|
+
const firstLine = (sub.split("\n")[0] ?? "").toLowerCase().trim();
|
|
8734
8836
|
const items = sub.split("\n").slice(1).filter((l) => l.trim().startsWith("-") || l.trim().startsWith("*")).map((l) => l.replace(/^[\s\-*]+/, "").trim()).filter(Boolean);
|
|
8735
8837
|
if (/breaking/.test(firstLine)) {
|
|
8736
8838
|
entry.breaking.push(...items);
|
|
@@ -8746,8 +8848,9 @@ function parseChangelog(content) {
|
|
|
8746
8848
|
for (const sub2 of subSections) {
|
|
8747
8849
|
for (const line of sub2.split("\n")) {
|
|
8748
8850
|
const breakingMatch = line.match(/BREAKING CHANGE[S]?:\s*(.+)/i);
|
|
8749
|
-
|
|
8750
|
-
|
|
8851
|
+
const breakingText = breakingMatch?.[1]?.trim();
|
|
8852
|
+
if (breakingText && !entry.breaking.includes(breakingText)) {
|
|
8853
|
+
entry.breaking.push(breakingText);
|
|
8751
8854
|
}
|
|
8752
8855
|
}
|
|
8753
8856
|
}
|
|
@@ -8789,7 +8892,8 @@ function registerMemoryImportChangelog(memory2) {
|
|
|
8789
8892
|
}
|
|
8790
8893
|
if (opts.versions) {
|
|
8791
8894
|
if (opts.versions === "latest") {
|
|
8792
|
-
|
|
8895
|
+
const latest = entries[0];
|
|
8896
|
+
entries = latest ? [latest] : [];
|
|
8793
8897
|
} else {
|
|
8794
8898
|
const requested = opts.versions.split(",").map((v) => v.trim());
|
|
8795
8899
|
entries = entries.filter((e) => requested.includes(e.version));
|
|
@@ -10191,7 +10295,7 @@ function parseDays(input) {
|
|
|
10191
10295
|
// src/commands/doctor.ts
|
|
10192
10296
|
import { existsSync as existsSync59 } from "fs";
|
|
10193
10297
|
import { stat } from "fs/promises";
|
|
10194
|
-
import "path";
|
|
10298
|
+
import path39 from "path";
|
|
10195
10299
|
import { execSync as execSync3 } from "child_process";
|
|
10196
10300
|
import "commander";
|
|
10197
10301
|
import {
|
|
@@ -10352,6 +10456,27 @@ function registerDoctor(program2) {
|
|
|
10352
10456
|
}
|
|
10353
10457
|
}
|
|
10354
10458
|
const config = await loadConfig7(paths);
|
|
10459
|
+
if (config.enforcement?.requireBriefingFirst) {
|
|
10460
|
+
const claudeSettings = path39.join(root, ".claude", "settings.local.json");
|
|
10461
|
+
let hasClaudeEnforcement = false;
|
|
10462
|
+
if (existsSync59(claudeSettings)) {
|
|
10463
|
+
try {
|
|
10464
|
+
const { readFile: readFile16 } = await import("fs/promises");
|
|
10465
|
+
const raw = await readFile16(claudeSettings, "utf8");
|
|
10466
|
+
hasClaudeEnforcement = raw.includes("haive enforce session-start") && raw.includes("haive enforce pre-tool-use");
|
|
10467
|
+
} catch {
|
|
10468
|
+
hasClaudeEnforcement = false;
|
|
10469
|
+
}
|
|
10470
|
+
}
|
|
10471
|
+
if (!hasClaudeEnforcement) {
|
|
10472
|
+
findings.push({
|
|
10473
|
+
severity: "info",
|
|
10474
|
+
code: "claude-enforcement-hooks-missing",
|
|
10475
|
+
message: "hAIve enforcement is enabled, but project-scoped Claude Code hooks are not installed.",
|
|
10476
|
+
fix: "haive install-hooks claude --scope project"
|
|
10477
|
+
});
|
|
10478
|
+
}
|
|
10479
|
+
}
|
|
10355
10480
|
if (!config.autoSessionEnd) {
|
|
10356
10481
|
findings.push({
|
|
10357
10482
|
severity: "info",
|
|
@@ -10366,7 +10491,7 @@ function registerDoctor(program2) {
|
|
|
10366
10491
|
timeout: 3e3,
|
|
10367
10492
|
stdio: ["ignore", "pipe", "ignore"]
|
|
10368
10493
|
}).trim();
|
|
10369
|
-
const cliVersion = "0.9.
|
|
10494
|
+
const cliVersion = "0.9.8";
|
|
10370
10495
|
if (legacyRaw && legacyRaw !== cliVersion) {
|
|
10371
10496
|
findings.push({
|
|
10372
10497
|
severity: "warn",
|
|
@@ -10968,13 +11093,164 @@ function registerMemoryConflictCandidates(memory2) {
|
|
|
10968
11093
|
});
|
|
10969
11094
|
}
|
|
10970
11095
|
|
|
11096
|
+
// src/commands/enforce.ts
|
|
11097
|
+
import { existsSync as existsSync67 } from "fs";
|
|
11098
|
+
import { mkdir as mkdir17 } from "fs/promises";
|
|
11099
|
+
import "commander";
|
|
11100
|
+
import {
|
|
11101
|
+
findProjectRoot as findProjectRoot46,
|
|
11102
|
+
hasRecentBriefingMarker,
|
|
11103
|
+
resolveBriefingBudget as resolveBriefingBudget3,
|
|
11104
|
+
resolveHaivePaths as resolveHaivePaths43,
|
|
11105
|
+
writeBriefingMarker
|
|
11106
|
+
} from "@hiveai/core";
|
|
11107
|
+
var MAX_STDIN_BYTES2 = 256 * 1024;
|
|
11108
|
+
function registerEnforce(program2) {
|
|
11109
|
+
const enforce = program2.command("enforce").description("Agent enforcement helpers used by hAIve-installed hooks.");
|
|
11110
|
+
enforce.command("session-start").description("Claude Code SessionStart hook: inject briefing and write a local briefing marker.").option("-d, --dir <dir>", "project root").option("--task <text>", "task text to rank memories").option("--source <name>", "marker source", "claude-session-start").option("--session-id <id>", "agent session id").action(async (opts) => {
|
|
11111
|
+
const payload = await readHookPayload();
|
|
11112
|
+
const root = resolveRoot(opts.dir, payload);
|
|
11113
|
+
if (!root) return;
|
|
11114
|
+
const paths = resolveHaivePaths43(root);
|
|
11115
|
+
if (!existsSync67(paths.haiveDir)) return;
|
|
11116
|
+
await mkdir17(paths.runtimeDir, { recursive: true });
|
|
11117
|
+
const sessionId = opts.sessionId ?? payload.session_id;
|
|
11118
|
+
const task = opts.task ?? payload.prompt ?? "Start an AI coding session in this hAIve-initialized project.";
|
|
11119
|
+
await writeBriefingMarker(paths, {
|
|
11120
|
+
sessionId,
|
|
11121
|
+
task,
|
|
11122
|
+
source: opts.source ?? "claude-session-start"
|
|
11123
|
+
});
|
|
11124
|
+
const budget = resolveBriefingBudget3("quick", {
|
|
11125
|
+
max_tokens: 2500,
|
|
11126
|
+
max_memories: 5,
|
|
11127
|
+
include_module_contexts: false
|
|
11128
|
+
});
|
|
11129
|
+
const briefing = await getBriefing(
|
|
11130
|
+
{
|
|
11131
|
+
task,
|
|
11132
|
+
files: [],
|
|
11133
|
+
max_tokens: budget.max_tokens,
|
|
11134
|
+
max_memories: budget.max_memories,
|
|
11135
|
+
include_project_context: true,
|
|
11136
|
+
include_module_contexts: budget.include_module_contexts,
|
|
11137
|
+
semantic: true,
|
|
11138
|
+
include_stale: false,
|
|
11139
|
+
track: true,
|
|
11140
|
+
format: "actions",
|
|
11141
|
+
symbols: [],
|
|
11142
|
+
min_semantic_score: 0.25,
|
|
11143
|
+
budget_preset: "quick"
|
|
11144
|
+
},
|
|
11145
|
+
{ paths }
|
|
11146
|
+
);
|
|
11147
|
+
console.log("hAIve briefing loaded. Agents must consult this before editing.");
|
|
11148
|
+
if (briefing.last_session) {
|
|
11149
|
+
console.log(`
|
|
11150
|
+
## Last session
|
|
11151
|
+
${briefing.last_session.body.slice(0, 1200)}`);
|
|
11152
|
+
}
|
|
11153
|
+
if (briefing.project_context?.content) {
|
|
11154
|
+
console.log(`
|
|
11155
|
+
## Project context
|
|
11156
|
+
${briefing.project_context.content.slice(0, 1800)}`);
|
|
11157
|
+
}
|
|
11158
|
+
if (briefing.memories.length > 0) {
|
|
11159
|
+
console.log("\n## Relevant memories");
|
|
11160
|
+
for (const memory2 of briefing.memories.slice(0, 6)) {
|
|
11161
|
+
console.log(`
|
|
11162
|
+
### ${memory2.id} (${memory2.scope}/${memory2.type}, ${memory2.confidence})`);
|
|
11163
|
+
console.log(memory2.body.slice(0, 1e3));
|
|
11164
|
+
}
|
|
11165
|
+
}
|
|
11166
|
+
for (const warning of briefing.setup_warnings) {
|
|
11167
|
+
console.log(`
|
|
11168
|
+
[setup warning] ${warning}`);
|
|
11169
|
+
}
|
|
11170
|
+
});
|
|
11171
|
+
enforce.command("pre-tool-use").description("Claude Code PreToolUse hook: block writes until hAIve briefing has been loaded.").option("-d, --dir <dir>", "project root").action(async (opts) => {
|
|
11172
|
+
const payload = await readHookPayload();
|
|
11173
|
+
const root = resolveRoot(opts.dir, payload);
|
|
11174
|
+
if (!root) return;
|
|
11175
|
+
const paths = resolveHaivePaths43(root);
|
|
11176
|
+
if (!existsSync67(paths.haiveDir)) return;
|
|
11177
|
+
if (!isWriteLikeTool(payload)) return;
|
|
11178
|
+
const ok = await hasRecentBriefingMarker(paths, payload.session_id);
|
|
11179
|
+
if (ok) return;
|
|
11180
|
+
const tool = payload.tool_name ?? "write tool";
|
|
11181
|
+
console.error(
|
|
11182
|
+
[
|
|
11183
|
+
"hAIve enforcement blocked this action.",
|
|
11184
|
+
`Tool: ${tool}`,
|
|
11185
|
+
"",
|
|
11186
|
+
"This project is initialized with hAIve. Load the team briefing before editing:",
|
|
11187
|
+
" haive enforce session-start",
|
|
11188
|
+
"or call MCP get_briefing / mem_relevant_to from your AI client.",
|
|
11189
|
+
"",
|
|
11190
|
+
"If this is intentional, a human can disable enforcement in .ai/haive.config.json:",
|
|
11191
|
+
' { "enforcement": { "requireBriefingFirst": false } }'
|
|
11192
|
+
].join("\n")
|
|
11193
|
+
);
|
|
11194
|
+
process.exit(2);
|
|
11195
|
+
});
|
|
11196
|
+
}
|
|
11197
|
+
async function readHookPayload() {
|
|
11198
|
+
const raw = await readStdin2(MAX_STDIN_BYTES2);
|
|
11199
|
+
if (!raw.trim()) return {};
|
|
11200
|
+
try {
|
|
11201
|
+
return JSON.parse(raw);
|
|
11202
|
+
} catch {
|
|
11203
|
+
return {};
|
|
11204
|
+
}
|
|
11205
|
+
}
|
|
11206
|
+
function resolveRoot(dir, payload) {
|
|
11207
|
+
try {
|
|
11208
|
+
return findProjectRoot46(dir ?? payload.cwd);
|
|
11209
|
+
} catch {
|
|
11210
|
+
return null;
|
|
11211
|
+
}
|
|
11212
|
+
}
|
|
11213
|
+
function isWriteLikeTool(payload) {
|
|
11214
|
+
const tool = payload.tool_name ?? "";
|
|
11215
|
+
if (["Edit", "Write", "MultiEdit", "NotebookEdit"].includes(tool)) return true;
|
|
11216
|
+
if (tool !== "Bash") return false;
|
|
11217
|
+
const command = String(payload.tool_input?.["command"] ?? "");
|
|
11218
|
+
return /\b(rm|mv|cp|mkdir|touch|tee|sed|perl|python|node|npm|pnpm|yarn|git)\b/.test(command) || />{1,2}/.test(command);
|
|
11219
|
+
}
|
|
11220
|
+
async function readStdin2(maxBytes) {
|
|
11221
|
+
if (process.stdin.isTTY) return "";
|
|
11222
|
+
return await new Promise((resolve) => {
|
|
11223
|
+
const chunks = [];
|
|
11224
|
+
let total = 0;
|
|
11225
|
+
let done = false;
|
|
11226
|
+
const finish = () => {
|
|
11227
|
+
if (done) return;
|
|
11228
|
+
done = true;
|
|
11229
|
+
resolve(Buffer.concat(chunks).toString("utf8"));
|
|
11230
|
+
};
|
|
11231
|
+
process.stdin.on("data", (c) => {
|
|
11232
|
+
total += c.length;
|
|
11233
|
+
if (total > maxBytes) {
|
|
11234
|
+
process.stdin.destroy();
|
|
11235
|
+
finish();
|
|
11236
|
+
return;
|
|
11237
|
+
}
|
|
11238
|
+
chunks.push(c);
|
|
11239
|
+
});
|
|
11240
|
+
process.stdin.on("end", finish);
|
|
11241
|
+
process.stdin.on("error", finish);
|
|
11242
|
+
setTimeout(finish, 2e3);
|
|
11243
|
+
});
|
|
11244
|
+
}
|
|
11245
|
+
|
|
10971
11246
|
// src/index.ts
|
|
10972
|
-
var program = new
|
|
10973
|
-
program.name("haive").description("hAIve \u2014 team-first persistent memory layer for AI coding agents").version("0.9.
|
|
11247
|
+
var program = new Command48();
|
|
11248
|
+
program.name("haive").description("hAIve \u2014 team-first persistent memory layer for AI coding agents").version("0.9.8");
|
|
10974
11249
|
registerInit(program);
|
|
10975
11250
|
registerWelcome(program);
|
|
10976
11251
|
registerResolveProject(program);
|
|
10977
11252
|
registerRuntime(program);
|
|
11253
|
+
registerEnforce(program);
|
|
10978
11254
|
registerMcp(program);
|
|
10979
11255
|
registerBriefing(program);
|
|
10980
11256
|
registerTui(program);
|