@hiveai/cli 0.13.9 → 0.14.0
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 +165 -54
- 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 Command59 } from "commander";
|
|
5
5
|
|
|
6
6
|
// src/commands/briefing.ts
|
|
7
7
|
import { existsSync as existsSync3 } from "fs";
|
|
@@ -199,7 +199,7 @@ async function getHotFiles(root, daysBack, maxHotFiles, filePaths) {
|
|
|
199
199
|
if (!f) continue;
|
|
200
200
|
counts.set(f, (counts.get(f) ?? 0) + 1);
|
|
201
201
|
}
|
|
202
|
-
let entries = [...counts.entries()].map(([
|
|
202
|
+
let entries = [...counts.entries()].map(([path56, changes]) => ({ path: path56, changes }));
|
|
203
203
|
const lowerPaths = filePaths.map((p) => p.toLowerCase());
|
|
204
204
|
if (lowerPaths.length > 0) {
|
|
205
205
|
entries = entries.filter((e) => lowerPaths.some((p) => e.path.toLowerCase().includes(p)));
|
|
@@ -3019,7 +3019,7 @@ ${SEED_FOOTER(stack)}` });
|
|
|
3019
3019
|
}
|
|
3020
3020
|
|
|
3021
3021
|
// src/commands/init.ts
|
|
3022
|
-
var HAIVE_GITHUB_ACTION_REF = `v${"0.
|
|
3022
|
+
var HAIVE_GITHUB_ACTION_REF = `v${"0.14.0"}`;
|
|
3023
3023
|
var PROJECT_CONTEXT_TEMPLATE = `# Project context
|
|
3024
3024
|
|
|
3025
3025
|
> Generated by \`haive init\`. Run \`haive init --bootstrap\` to auto-fill from your codebase,
|
|
@@ -4089,10 +4089,13 @@ import {
|
|
|
4089
4089
|
literalMatchesAnyToken as literalMatchesAnyToken22,
|
|
4090
4090
|
loadCodeMap as loadCodeMap5,
|
|
4091
4091
|
loadConfig as loadConfig3,
|
|
4092
|
+
hashProjectContext,
|
|
4092
4093
|
loadMemoriesFromDir as loadMemoriesFromDir15,
|
|
4093
4094
|
loadUsageIndex as loadUsageIndex8,
|
|
4094
4095
|
memoryMatchesAnchorPaths as memoryMatchesAnchorPaths22,
|
|
4096
|
+
projectContextRecentlyEmitted,
|
|
4095
4097
|
rankMemoriesLexical as rankMemoriesLexical2,
|
|
4098
|
+
recordProjectContextEmission,
|
|
4096
4099
|
queryCodeMap as queryCodeMap2,
|
|
4097
4100
|
resolveBriefingBudget as resolveBriefingBudget2,
|
|
4098
4101
|
serializeMemory as serializeMemory10,
|
|
@@ -5711,6 +5714,9 @@ var GetBriefingInputSchema = {
|
|
|
5711
5714
|
),
|
|
5712
5715
|
max_memories: z19.number().int().positive().default(8).describe("Cap on memories surfaced regardless of token budget"),
|
|
5713
5716
|
include_project_context: z19.boolean().default(true),
|
|
5717
|
+
dedupe_project_context: z19.boolean().optional().describe(
|
|
5718
|
+
"Token saver (default ON): skip re-emitting the project-context body if an identical copy was already sent within the last few minutes this session (the agent still has it). Set false to always include it."
|
|
5719
|
+
),
|
|
5714
5720
|
include_module_contexts: z19.boolean().default(true),
|
|
5715
5721
|
semantic: z19.boolean().default(true).describe(
|
|
5716
5722
|
"Use semantic ranking when a task is provided (requires `haive embeddings index`)."
|
|
@@ -5918,7 +5924,17 @@ async function getBriefing(input, ctx) {
|
|
|
5918
5924
|
}
|
|
5919
5925
|
}
|
|
5920
5926
|
}
|
|
5921
|
-
|
|
5927
|
+
let projectContextRaw = input.include_project_context && existsSync21(ctx.paths.projectContext) ? await readFile52(ctx.paths.projectContext, "utf8") : "";
|
|
5928
|
+
let contextOmittedRecent = false;
|
|
5929
|
+
if (projectContextRaw && input.dedupe_project_context !== false) {
|
|
5930
|
+
const ctxHash = hashProjectContext(projectContextRaw);
|
|
5931
|
+
if (await projectContextRecentlyEmitted(ctx.paths, ctxHash)) {
|
|
5932
|
+
contextOmittedRecent = true;
|
|
5933
|
+
projectContextRaw = "";
|
|
5934
|
+
} else {
|
|
5935
|
+
await recordProjectContextEmission(ctx.paths, ctxHash);
|
|
5936
|
+
}
|
|
5937
|
+
}
|
|
5922
5938
|
const isTemplateContext = projectContextRaw.includes("TODO \u2014 high-level overview") || projectContextRaw.includes("Generated by `haive init`");
|
|
5923
5939
|
const setupWarnings = [];
|
|
5924
5940
|
let autoContextGenerated = false;
|
|
@@ -6186,7 +6202,11 @@ When done, call \`mem_session_end\` to acknowledge \u2014 this clears the pendin
|
|
|
6186
6202
|
search_mode: searchMode,
|
|
6187
6203
|
inferred_modules: inferred,
|
|
6188
6204
|
...lastSession ? { last_session: lastSession } : {},
|
|
6189
|
-
project_context:
|
|
6205
|
+
project_context: contextOmittedRecent ? {
|
|
6206
|
+
content: "(project context unchanged \u2014 omitted to save tokens; it was provided earlier this session. Pass dedupe_project_context:false to force a full copy.)",
|
|
6207
|
+
truncated: false,
|
|
6208
|
+
omitted_recent: true
|
|
6209
|
+
} : adaptiveTrim ? {
|
|
6190
6210
|
content: "(adaptive briefing: auto-generated context omitted \u2014 no team-specific policy matched, so a capable model needs nothing extra here)",
|
|
6191
6211
|
truncated: false,
|
|
6192
6212
|
...isTemplateContext && !autoContextGenerated ? { is_template: true } : {},
|
|
@@ -7504,7 +7524,7 @@ async function patternDetect(input, ctx) {
|
|
|
7504
7524
|
for (const [p, { count, tools }] of pathCounts) {
|
|
7505
7525
|
if (count < HOT_FILE_MIN) continue;
|
|
7506
7526
|
if (tools.has("mem_tried") || tools.has("mem_observe")) continue;
|
|
7507
|
-
if (CONFIG_PATTERNS.some((
|
|
7527
|
+
if (CONFIG_PATTERNS.some((cp2) => path122.basename(p).includes(cp2))) continue;
|
|
7508
7528
|
const slug = p.replace(/[^a-z0-9]/g, "-").replace(/-+/g, "-").slice(0, 40);
|
|
7509
7529
|
matches.push({
|
|
7510
7530
|
kind: "hot_file",
|
|
@@ -7938,7 +7958,7 @@ When done, respond with: "Imported N memories: [list of IDs]" or "Nothing action
|
|
|
7938
7958
|
};
|
|
7939
7959
|
}
|
|
7940
7960
|
var SERVER_NAME = "haive";
|
|
7941
|
-
var SERVER_VERSION = "0.
|
|
7961
|
+
var SERVER_VERSION = "0.14.0";
|
|
7942
7962
|
function jsonResult(data) {
|
|
7943
7963
|
return {
|
|
7944
7964
|
content: [
|
|
@@ -8687,6 +8707,7 @@ function createHaiveServer(options = {}) {
|
|
|
8687
8707
|
"anti_patterns_check",
|
|
8688
8708
|
[
|
|
8689
8709
|
"Scan a diff (or set of paths) against documented attempt/gotcha memories.",
|
|
8710
|
+
"[Diff-scan layer: the MEMORY-MATCH component. `pre_commit_check` combines this with sensors + stale checks; `haive enforce check` is the gate.]",
|
|
8690
8711
|
"Surfaces 'you are about to repeat a known mistake' warnings BEFORE you commit.",
|
|
8691
8712
|
"",
|
|
8692
8713
|
"USE BEFORE finalizing a non-trivial change. Cheap and high-signal: the only",
|
|
@@ -8830,6 +8851,7 @@ function createHaiveServer(options = {}) {
|
|
|
8830
8851
|
"pre_commit_check",
|
|
8831
8852
|
[
|
|
8832
8853
|
"One-shot 'should I block this commit?' check. Combines three signals:",
|
|
8854
|
+
"[Diff-scan layer: the COMBINED check (sensors + anti-patterns + stale). `haive enforce check` is the gate that runs this at commit time.]",
|
|
8833
8855
|
"",
|
|
8834
8856
|
" 1. anti_patterns_check \u2014 known gotchas/attempts that match the diff",
|
|
8835
8857
|
" 2. mem_for_files \u2014 conventions/decisions anchored to touched files",
|
|
@@ -13308,8 +13330,8 @@ function registerDoctor(program2) {
|
|
|
13308
13330
|
fix: "haive init"
|
|
13309
13331
|
});
|
|
13310
13332
|
} else {
|
|
13311
|
-
const { readFile:
|
|
13312
|
-
const content = await
|
|
13333
|
+
const { readFile: readFile27 } = await import("fs/promises");
|
|
13334
|
+
const content = await readFile27(paths.projectContext, "utf8");
|
|
13313
13335
|
const isTemplate = content.includes("TODO \u2014 high-level overview") || content.includes("Generated by `haive init`");
|
|
13314
13336
|
if (isTemplate) {
|
|
13315
13337
|
findings.push({
|
|
@@ -13483,8 +13505,8 @@ function registerDoctor(program2) {
|
|
|
13483
13505
|
let hasClaudeEnforcement = false;
|
|
13484
13506
|
if (existsSync68(claudeSettings)) {
|
|
13485
13507
|
try {
|
|
13486
|
-
const { readFile:
|
|
13487
|
-
const raw = await
|
|
13508
|
+
const { readFile: readFile27 } = await import("fs/promises");
|
|
13509
|
+
const raw = await readFile27(claudeSettings, "utf8");
|
|
13488
13510
|
hasClaudeEnforcement = raw.includes("haive enforce session-start") && raw.includes("haive enforce pre-tool-use");
|
|
13489
13511
|
} catch {
|
|
13490
13512
|
hasClaudeEnforcement = false;
|
|
@@ -13507,7 +13529,7 @@ function registerDoctor(program2) {
|
|
|
13507
13529
|
fix: "Edit .ai/haive.config.json: set autoSessionEnd: true (or re-run `haive init` without --manual)."
|
|
13508
13530
|
});
|
|
13509
13531
|
}
|
|
13510
|
-
findings.push(...await collectInstallFindings(root, "0.
|
|
13532
|
+
findings.push(...await collectInstallFindings(root, "0.14.0"));
|
|
13511
13533
|
findings.push(...await collectToolchainFindings(root));
|
|
13512
13534
|
try {
|
|
13513
13535
|
const legacyRaw = execSync3("haive-mcp --version", {
|
|
@@ -13515,7 +13537,7 @@ function registerDoctor(program2) {
|
|
|
13515
13537
|
timeout: 3e3,
|
|
13516
13538
|
stdio: ["ignore", "pipe", "ignore"]
|
|
13517
13539
|
}).trim();
|
|
13518
|
-
const cliVersion = "0.
|
|
13540
|
+
const cliVersion = "0.14.0";
|
|
13519
13541
|
if (legacyRaw && legacyRaw !== cliVersion) {
|
|
13520
13542
|
findings.push({
|
|
13521
13543
|
severity: "warn",
|
|
@@ -14748,52 +14770,73 @@ ${briefing.project_context.content.slice(0, 1800)}`);
|
|
|
14748
14770
|
[setup warning] ${warning}`);
|
|
14749
14771
|
}
|
|
14750
14772
|
});
|
|
14751
|
-
enforce.command("pre-tool-use").description("Claude Code PreToolUse hook:
|
|
14773
|
+
enforce.command("pre-tool-use").description("Claude Code PreToolUse hook: surface the relevant team policy for the edited file (advise; configurable to block).").option("-d, --dir <dir>", "project root").action(async (opts) => {
|
|
14752
14774
|
const payload = await readHookPayload();
|
|
14753
14775
|
const root = resolveRoot(opts.dir, payload);
|
|
14754
14776
|
if (!root) return;
|
|
14755
14777
|
const paths = resolveHaivePaths48(root);
|
|
14756
14778
|
if (!existsSync75(paths.haiveDir)) return;
|
|
14757
14779
|
if (!isWriteLikeTool(payload)) return;
|
|
14758
|
-
const
|
|
14759
|
-
if (
|
|
14760
|
-
|
|
14761
|
-
|
|
14762
|
-
|
|
14763
|
-
|
|
14764
|
-
|
|
14780
|
+
const config = await loadConfig13(paths);
|
|
14781
|
+
if (config.enforcement?.requireBriefingFirst === false) return;
|
|
14782
|
+
const gate = config.enforcement?.preEditGate ?? "advise";
|
|
14783
|
+
const targetFiles = extractToolPaths(payload, root);
|
|
14784
|
+
const hasMarker = await hasRecentBriefingMarker2(paths, payload.session_id);
|
|
14785
|
+
const missing = targetFiles.length > 0 ? await missingRequiredMemoriesForFiles(paths, targetFiles, payload.session_id) : [];
|
|
14786
|
+
if (hasMarker && missing.length === 0) return;
|
|
14787
|
+
if (targetFiles.length > 0) {
|
|
14788
|
+
await recordFilesIntoBriefingMarker(paths, targetFiles, missing, payload.session_id).catch(() => {
|
|
14789
|
+
});
|
|
14790
|
+
}
|
|
14791
|
+
const contextText = buildPreEditContext(payload.tool_name ?? "write tool", targetFiles, missing, hasMarker);
|
|
14792
|
+
if (gate === "block") {
|
|
14765
14793
|
console.error(
|
|
14766
|
-
|
|
14767
|
-
"hAIve enforcement blocked this action.",
|
|
14768
|
-
`Tool: ${payload.tool_name ?? "write tool"}`,
|
|
14769
|
-
`Files: ${targetFiles.slice(0, 6).join(", ")}`,
|
|
14770
|
-
"",
|
|
14771
|
-
"These files have required hAIve context that was not in the current briefing:",
|
|
14772
|
-
...ids.map((id) => ` - ${id}`),
|
|
14773
|
-
"",
|
|
14774
|
-
"Load the targeted briefing before editing:",
|
|
14775
|
-
` ${briefingCommandForFiles(targetFiles)}`
|
|
14776
|
-
].join("\n")
|
|
14794
|
+
contextText + '\n\nThe relevant context is now recorded \u2014 re-issue the same edit to proceed (no `haive briefing` command needed). To make this advisory instead of blocking, set `{ "enforcement": { "preEditGate": "advise" } }` in .ai/haive.config.json.'
|
|
14777
14795
|
);
|
|
14778
14796
|
process.exit(2);
|
|
14779
14797
|
}
|
|
14780
|
-
|
|
14781
|
-
console.error(
|
|
14782
|
-
[
|
|
14783
|
-
"hAIve enforcement blocked this action.",
|
|
14784
|
-
`Tool: ${tool}`,
|
|
14785
|
-
"",
|
|
14786
|
-
"This project is initialized with hAIve. Load the team briefing before editing:",
|
|
14787
|
-
" haive enforce session-start",
|
|
14788
|
-
"or call MCP get_briefing / mem_relevant_to from your AI client.",
|
|
14789
|
-
"",
|
|
14790
|
-
"If this is intentional, a human can disable enforcement in .ai/haive.config.json:",
|
|
14791
|
-
' { "enforcement": { "requireBriefingFirst": false } }'
|
|
14792
|
-
].join("\n")
|
|
14793
|
-
);
|
|
14794
|
-
process.exit(2);
|
|
14798
|
+
emitPreToolUseContext(contextText);
|
|
14795
14799
|
});
|
|
14796
14800
|
}
|
|
14801
|
+
async function recordFilesIntoBriefingMarker(paths, files, missing, sessionId) {
|
|
14802
|
+
const existing = await readRecentBriefingMarker(paths, sessionId);
|
|
14803
|
+
const ids = new Set(existing?.memory_ids ?? []);
|
|
14804
|
+
for (const { memory: memory2 } of missing) ids.add(memory2.frontmatter.id);
|
|
14805
|
+
await writeBriefingMarker3(paths, {
|
|
14806
|
+
sessionId,
|
|
14807
|
+
task: existing?.task ?? "pre-edit auto-briefing",
|
|
14808
|
+
source: "haive-pre-edit",
|
|
14809
|
+
files,
|
|
14810
|
+
memoryIds: [...ids]
|
|
14811
|
+
});
|
|
14812
|
+
}
|
|
14813
|
+
function buildPreEditContext(tool, files, missing, hasMarker) {
|
|
14814
|
+
const lines = ["hAIve \u2014 relevant team policy for this edit", `Tool: ${tool}`];
|
|
14815
|
+
if (files.length > 0) lines.push(`Files: ${files.slice(0, 6).join(", ")}`);
|
|
14816
|
+
if (missing.length > 0) {
|
|
14817
|
+
lines.push("", "Consult these before editing (anchored to the files you are touching):");
|
|
14818
|
+
for (const { memory: memory2 } of missing.slice(0, 5)) {
|
|
14819
|
+
const fm = memory2.frontmatter;
|
|
14820
|
+
lines.push("", `### ${fm.id} (${fm.scope}/${fm.type})`, memory2.body.trim().slice(0, 900));
|
|
14821
|
+
}
|
|
14822
|
+
} else if (!hasMarker) {
|
|
14823
|
+
lines.push(
|
|
14824
|
+
"",
|
|
14825
|
+
"No team briefing was loaded yet this session. Proceeding \u2014 but for substantive work call get_briefing / mem_relevant_to for richer context."
|
|
14826
|
+
);
|
|
14827
|
+
}
|
|
14828
|
+
return lines.join("\n");
|
|
14829
|
+
}
|
|
14830
|
+
function emitPreToolUseContext(text) {
|
|
14831
|
+
console.log(
|
|
14832
|
+
JSON.stringify({
|
|
14833
|
+
hookSpecificOutput: {
|
|
14834
|
+
hookEventName: "PreToolUse",
|
|
14835
|
+
additionalContext: text
|
|
14836
|
+
}
|
|
14837
|
+
})
|
|
14838
|
+
);
|
|
14839
|
+
}
|
|
14797
14840
|
async function buildFinishReport(dir) {
|
|
14798
14841
|
const root = findProjectRoot52(dir);
|
|
14799
14842
|
const paths = resolveHaivePaths48(root);
|
|
@@ -15124,7 +15167,7 @@ async function buildEnforcementReport(dir, stage, sessionId) {
|
|
|
15124
15167
|
findings: [{ severity: "info", code: "enforcement-off", message: "hAIve enforcement is disabled." }]
|
|
15125
15168
|
});
|
|
15126
15169
|
}
|
|
15127
|
-
findings.push(...await inspectIntegrationVersions(root, "0.
|
|
15170
|
+
findings.push(...await inspectIntegrationVersions(root, "0.14.0"));
|
|
15128
15171
|
if (config.enforcement?.requireBriefingFirst !== false && stage !== "ci") {
|
|
15129
15172
|
const hasBriefing = await hasRecentBriefingMarker2(paths, sessionId);
|
|
15130
15173
|
findings.push(hasBriefing ? { severity: "ok", code: "briefing-loaded", message: "A recent hAIve briefing marker exists." } : {
|
|
@@ -15242,7 +15285,7 @@ async function verifyMemoryPolicy(paths, config) {
|
|
|
15242
15285
|
}
|
|
15243
15286
|
async function verifyDecisionCoverage(paths, stage, sessionId) {
|
|
15244
15287
|
if (!existsSync75(paths.memoriesDir)) return [];
|
|
15245
|
-
const changedFiles = await getChangedFiles(paths.root, stage);
|
|
15288
|
+
const changedFiles = (await getChangedFiles(paths.root, stage)).filter((f) => !isGeneratedArtifact(f));
|
|
15246
15289
|
if (changedFiles.length === 0) {
|
|
15247
15290
|
return [{ severity: "info", code: "decision-coverage-no-changes", message: "No changed files to match against policy memories." }];
|
|
15248
15291
|
}
|
|
@@ -16039,8 +16082,10 @@ async function missingRequiredMemoriesForFiles(paths, files, sessionId) {
|
|
|
16039
16082
|
return memoryMatchesAnchorPaths6(memory2, files);
|
|
16040
16083
|
}).map(({ memory: memory2, filePath }) => ({ memory: memory2, filePath }));
|
|
16041
16084
|
}
|
|
16042
|
-
function
|
|
16043
|
-
|
|
16085
|
+
function isGeneratedArtifact(file) {
|
|
16086
|
+
if (file === ".ai/project-context.md" || file === ".ai/code-map.json") return true;
|
|
16087
|
+
if (file.startsWith(".ai/.cache/") || file.startsWith(".ai/.runtime/") || file.startsWith(".ai/.usage/")) return true;
|
|
16088
|
+
return false;
|
|
16044
16089
|
}
|
|
16045
16090
|
async function readStdin2(maxBytes) {
|
|
16046
16091
|
if (process.stdin.isTTY) return "";
|
|
@@ -16151,7 +16196,9 @@ function registerSensors(program2) {
|
|
|
16151
16196
|
if (row.last_fired) console.log(` ${ui.dim("last fired:")} ${row.last_fired}`);
|
|
16152
16197
|
}
|
|
16153
16198
|
});
|
|
16154
|
-
sensors.command("check").description(
|
|
16199
|
+
sensors.command("check").description(
|
|
16200
|
+
"Run regex sensors against a diff (the deterministic/computational layer); defaults to `git diff --cached`.\n Diff-scan layers: `sensors check` (regex) and `anti_patterns_check` (memory match) are components;\n `pre_commit_check` combines them; `haive enforce check` is THE gate that runs at commit."
|
|
16201
|
+
).option("--diff-file <path>", "read unified diff from a file instead of staged changes").option("--json", "emit JSON", false).option("-d, --dir <dir>", "project root").action(async (opts) => {
|
|
16155
16202
|
const root = findProjectRoot53(opts.dir);
|
|
16156
16203
|
const paths = resolveHaivePaths49(root);
|
|
16157
16204
|
const memories = await runnableSensorMemories(paths);
|
|
@@ -16634,9 +16681,72 @@ function warnNum(n) {
|
|
|
16634
16681
|
return n > 0 ? ui.yellow(String(n)) : String(n);
|
|
16635
16682
|
}
|
|
16636
16683
|
|
|
16684
|
+
// src/commands/dev-link.ts
|
|
16685
|
+
import { execFile as execFile3 } from "child_process";
|
|
16686
|
+
import { cp, readFile as readFile26 } from "fs/promises";
|
|
16687
|
+
import { existsSync as existsSync79 } from "fs";
|
|
16688
|
+
import path55 from "path";
|
|
16689
|
+
import { promisify as promisify3 } from "util";
|
|
16690
|
+
import "commander";
|
|
16691
|
+
import { findProjectRoot as findProjectRoot56 } from "@hiveai/core";
|
|
16692
|
+
var exec3 = promisify3(execFile3);
|
|
16693
|
+
function registerDevLink(program2) {
|
|
16694
|
+
const dev = program2.commands.find((c) => c.name() === "dev") ?? program2.command("dev").description("Developer utilities for working on hAIve itself.");
|
|
16695
|
+
dev.command("link").description("Hot-swap this repo's built dist into the global @hiveai install so `haive` runs your local code.").option("-d, --dir <dir>", "repo root (default: discovered from cwd)").option("--json", "emit a machine-readable summary", false).action(async (opts) => {
|
|
16696
|
+
const root = findProjectRoot56(opts.dir);
|
|
16697
|
+
if (!existsSync79(path55.join(root, "packages", "cli", "dist", "index.js"))) {
|
|
16698
|
+
ui.error(`Not the hAIve monorepo (no packages/cli/dist) at ${root}. Run \`pnpm -r build\` first, or pass --dir.`);
|
|
16699
|
+
process.exitCode = 1;
|
|
16700
|
+
return;
|
|
16701
|
+
}
|
|
16702
|
+
let globalModules;
|
|
16703
|
+
try {
|
|
16704
|
+
globalModules = (await exec3("npm", ["root", "-g"])).stdout.trim();
|
|
16705
|
+
} catch {
|
|
16706
|
+
globalModules = path55.join(path55.dirname(path55.dirname(process.execPath)), "lib", "node_modules");
|
|
16707
|
+
}
|
|
16708
|
+
const globalHive = path55.join(globalModules, "@hiveai");
|
|
16709
|
+
if (!existsSync79(globalHive)) {
|
|
16710
|
+
ui.error(`No global @hiveai install at ${globalHive}. Install once with \`npm i -g @hiveai/cli\`, then re-run.`);
|
|
16711
|
+
process.exitCode = 1;
|
|
16712
|
+
return;
|
|
16713
|
+
}
|
|
16714
|
+
const linked = [];
|
|
16715
|
+
const copyDist = async (fromPkg, toDistDir) => {
|
|
16716
|
+
const from = path55.join(root, "packages", fromPkg, "dist");
|
|
16717
|
+
if (!existsSync79(from) || !existsSync79(path55.dirname(toDistDir))) return;
|
|
16718
|
+
await cp(from, toDistDir, { recursive: true });
|
|
16719
|
+
linked.push(path55.relative(globalModules, toDistDir));
|
|
16720
|
+
};
|
|
16721
|
+
for (const pkg of ["cli", "mcp"]) {
|
|
16722
|
+
await copyDist(pkg, path55.join(globalHive, pkg, "dist"));
|
|
16723
|
+
for (const nested of ["core", "embeddings"]) {
|
|
16724
|
+
await copyDist(nested, path55.join(globalHive, pkg, "node_modules", "@hiveai", nested, "dist"));
|
|
16725
|
+
}
|
|
16726
|
+
}
|
|
16727
|
+
await copyDist("core", path55.join(globalHive, "core", "dist"));
|
|
16728
|
+
let version = "unknown";
|
|
16729
|
+
try {
|
|
16730
|
+
version = JSON.parse(await readFile26(path55.join(root, "package.json"), "utf8")).version ?? "unknown";
|
|
16731
|
+
} catch {
|
|
16732
|
+
}
|
|
16733
|
+
if (opts.json) {
|
|
16734
|
+
console.log(JSON.stringify({ ok: linked.length > 0, version, global_root: globalHive, linked }, null, 2));
|
|
16735
|
+
return;
|
|
16736
|
+
}
|
|
16737
|
+
if (linked.length === 0) {
|
|
16738
|
+
ui.warn("Nothing linked \u2014 no matching dist targets were found in the global install.");
|
|
16739
|
+
return;
|
|
16740
|
+
}
|
|
16741
|
+
ui.success(`Linked local dist (v${version}) into the global @hiveai install:`);
|
|
16742
|
+
for (const t of linked) console.log(` ${ui.dim("\u2192")} ${t}`);
|
|
16743
|
+
console.log(ui.dim("The global `haive` now runs your local build (git hooks + MCP included)."));
|
|
16744
|
+
});
|
|
16745
|
+
}
|
|
16746
|
+
|
|
16637
16747
|
// src/index.ts
|
|
16638
|
-
var program = new
|
|
16639
|
-
program.name("haive").description("hAIve - repo-native memory and context policy for coding-agent harnesses").version("0.
|
|
16748
|
+
var program = new Command59();
|
|
16749
|
+
program.name("haive").description("hAIve - repo-native memory and context policy for coding-agent harnesses").version("0.14.0").option("--advanced", "show maintenance and experimental commands in help");
|
|
16640
16750
|
registerInit(program);
|
|
16641
16751
|
registerWelcome(program);
|
|
16642
16752
|
registerResolveProject(program);
|
|
@@ -16647,6 +16757,7 @@ registerAgent(program);
|
|
|
16647
16757
|
registerSensors(program);
|
|
16648
16758
|
registerIngest(program);
|
|
16649
16759
|
registerDashboard(program);
|
|
16760
|
+
registerDevLink(program);
|
|
16650
16761
|
registerMcp(program);
|
|
16651
16762
|
registerBriefing(program);
|
|
16652
16763
|
registerTui(program);
|