hippo-memory 1.23.0 → 1.24.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/README.md +16 -5
- package/bin/hippo.js +2 -2
- package/dist/ablation.d.ts +93 -0
- package/dist/ablation.d.ts.map +1 -0
- package/dist/ablation.js +138 -0
- package/dist/ablation.js.map +1 -0
- package/dist/ambient.d.ts.map +1 -1
- package/dist/ambient.js +2 -1
- package/dist/ambient.js.map +1 -1
- package/dist/api.d.ts +37 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +88 -11
- package/dist/api.js.map +1 -1
- package/dist/benchmarks/e1.3/scenarios.json +2587 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +117 -18
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +8 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +2 -0
- package/dist/config.js.map +1 -1
- package/dist/connectors/github/backfill.js +4 -4
- package/dist/connectors/github/cli-impl.js +6 -6
- package/dist/connectors/github/dlq.js +14 -14
- package/dist/connectors/slack/backfill.js +1 -1
- package/dist/connectors/slack/dlq.js +10 -10
- package/dist/connectors/slack/workspaces.js +4 -4
- package/dist/consolidate.d.ts.map +1 -1
- package/dist/consolidate.js +27 -5
- package/dist/consolidate.js.map +1 -1
- package/dist/dag.js +6 -6
- package/dist/dashboard.js +7 -7
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +55 -4
- package/dist/db.js.map +1 -1
- package/dist/hooks.js +24 -24
- package/dist/importers.d.ts +28 -0
- package/dist/importers.d.ts.map +1 -1
- package/dist/importers.js +412 -1
- package/dist/importers.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +44 -7
- package/dist/mcp/server.js.map +1 -1
- package/dist/memory.d.ts +9 -0
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +29 -6
- package/dist/memory.js.map +1 -1
- package/dist/physics-state.d.ts.map +1 -1
- package/dist/physics-state.js +4 -3
- package/dist/physics-state.js.map +1 -1
- package/dist/physics.d.ts.map +1 -1
- package/dist/physics.js +8 -1
- package/dist/physics.js.map +1 -1
- package/dist/predictions.js +67 -67
- package/dist/project-identity.d.ts +84 -0
- package/dist/project-identity.d.ts.map +1 -0
- package/dist/project-identity.js +184 -0
- package/dist/project-identity.js.map +1 -0
- package/dist/refine-llm.js +13 -13
- package/dist/replay.d.ts.map +1 -1
- package/dist/replay.js +4 -1
- package/dist/replay.js.map +1 -1
- package/dist/search.d.ts +14 -0
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +36 -7
- package/dist/search.js.map +1 -1
- package/dist/secret-detect.d.ts +33 -0
- package/dist/secret-detect.d.ts.map +1 -0
- package/dist/secret-detect.js +70 -0
- package/dist/secret-detect.js.map +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +11 -0
- package/dist/server.js.map +1 -1
- package/dist/shared.d.ts +9 -1
- package/dist/shared.d.ts.map +1 -1
- package/dist/shared.js +67 -16
- package/dist/shared.js.map +1 -1
- package/dist/src/ablation.js +138 -0
- package/dist/src/ablation.js.map +1 -0
- package/dist/src/ambient.js +2 -1
- package/dist/src/ambient.js.map +1 -1
- package/dist/src/api.js +88 -11
- package/dist/src/api.js.map +1 -1
- package/dist/src/cli.js +117 -18
- package/dist/src/cli.js.map +1 -1
- package/dist/src/config.js +2 -0
- package/dist/src/config.js.map +1 -1
- package/dist/src/connectors/github/backfill.js +4 -4
- package/dist/src/connectors/github/cli-impl.js +6 -6
- package/dist/src/connectors/github/dlq.js +14 -14
- package/dist/src/connectors/slack/backfill.js +1 -1
- package/dist/src/connectors/slack/dlq.js +10 -10
- package/dist/src/connectors/slack/workspaces.js +4 -4
- package/dist/src/consolidate.js +27 -5
- package/dist/src/consolidate.js.map +1 -1
- package/dist/src/dag.js +6 -6
- package/dist/src/dashboard.js +7 -7
- package/dist/src/db.js +55 -4
- package/dist/src/db.js.map +1 -1
- package/dist/src/hooks.js +24 -24
- package/dist/src/importers.js +412 -1
- package/dist/src/importers.js.map +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcp/server.js +44 -7
- package/dist/src/mcp/server.js.map +1 -1
- package/dist/src/memory.js +29 -6
- package/dist/src/memory.js.map +1 -1
- package/dist/src/physics-state.js +4 -3
- package/dist/src/physics-state.js.map +1 -1
- package/dist/src/physics.js +8 -1
- package/dist/src/physics.js.map +1 -1
- package/dist/src/predictions.js +67 -67
- package/dist/src/project-identity.js +184 -0
- package/dist/src/project-identity.js.map +1 -0
- package/dist/src/refine-llm.js +13 -13
- package/dist/src/replay.js +4 -1
- package/dist/src/replay.js.map +1 -1
- package/dist/src/search.js +36 -7
- package/dist/src/search.js.map +1 -1
- package/dist/src/secret-detect.js +70 -0
- package/dist/src/secret-detect.js.map +1 -0
- package/dist/src/server.js +11 -0
- package/dist/src/server.js.map +1 -1
- package/dist/src/shared.js +67 -16
- package/dist/src/shared.js.map +1 -1
- package/dist/src/store.js +66 -11
- package/dist/src/store.js.map +1 -1
- package/dist/src/version.js +1 -1
- package/dist/src/working-memory.js +19 -19
- package/dist/store.d.ts +15 -0
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +66 -11
- package/dist/store.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/working-memory.js +19 -19
- package/dist-ui/index.html +12 -12
- package/extensions/openclaw-plugin/index.ts +650 -650
- package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
- package/extensions/openclaw-plugin/package.json +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +3 -1
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAyBH,OAAO,EASL,WAAW,EAEZ,MAAM,aAAa,CAAC;AAqGrB,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AA4ChC,kFAAkF;AAClF,wBAAgB,8BAA8B,IAAI,IAAI,CAErD;AAu4ED;;;GAGG;AACH,oHAAoH;AACpH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,GAAG,CAAC,WAAW,GAAG,IAAI,CAkD/D;AA8vFD,oHAAoH;AACpH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,KAAK,CAAC;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC,EACtF,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,MAAkB,GAC1B,IAAI,CA6BN"}
|
package/dist/cli.js
CHANGED
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
* hippo decide "<decision>" [--context "<why>"] [--supersedes <id>]
|
|
26
26
|
* hippo wm <push|read|clear|flush>
|
|
27
27
|
*/
|
|
28
|
+
import { evalNow, isRecallBoostAblated } from './ablation.js';
|
|
28
29
|
import * as path from 'path';
|
|
29
30
|
import * as fs from 'fs';
|
|
30
31
|
import * as os from 'os';
|
|
@@ -32,6 +33,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
32
33
|
import { execFileSync, execSync, spawn } from 'child_process';
|
|
33
34
|
import { installJsonHooks, uninstallJsonHooks, resolveJsonHookPaths, detectInstalledTools, defaultSleepLogPath, ensureCodexWrapperInstalled, installCodexWrapper, uninstallCodexWrapper, resolveCodexSessionTranscript, resolveCodexWrapperPaths, installOpencodePlugin, uninstallOpencodePlugin, resolveOpencodePluginPath, } from './hooks.js';
|
|
34
35
|
import { createMemory, calculateStrength, calculateRewardFactor, deriveHalfLife, resolveConfidence, computeSchemaFit, Layer, } from './memory.js';
|
|
36
|
+
import { resolveProjectIdentity } from './project-identity.js';
|
|
35
37
|
import { getHippoRoot, isInitialized, initStore, writeEntry, readEntry, deleteEntry, loadAllEntries, loadSearchEntries, loadIndex, saveIndex, loadStats, updateStats, saveActiveTaskSnapshot, loadActiveTaskSnapshot, clearActiveTaskSnapshot, appendSessionEvent, listSessionEvents, listMemoryConflicts, resolveConflict, saveSessionHandoff, loadLatestHandoff, loadHandoffById, RECALL_DEFAULT_DENY_SCOPES, } from './store.js';
|
|
36
38
|
import { markRetrieved, hybridSearch, physicsSearch, explainMatch, textOverlap } from './search.js';
|
|
37
39
|
import { renderTraceContent, parseSteps } from './trace.js';
|
|
@@ -50,7 +52,7 @@ import { extractPathTags } from './path-context.js';
|
|
|
50
52
|
import { detectScope } from './scope.js';
|
|
51
53
|
import { getGlobalRoot, initGlobal, shareMemory, listPeers, autoShare, transferScore, searchBothHybrid, syncGlobalToLocal, } from './shared.js';
|
|
52
54
|
import { DAILY_TASK_NAME, buildDailyRunnerCommand, listRegisteredWorkspaces, registerWorkspace, runDailyMaintenance, } from './scheduler.js';
|
|
53
|
-
import { importChatGPT, importClaude, importCursor, importGenericFile, importMarkdown, } from './importers.js';
|
|
55
|
+
import { importChatGPT, importClaude, importCursor, importGenericFile, importMarkdown, importVault, } from './importers.js';
|
|
54
56
|
import { cmdCapture } from './capture.js';
|
|
55
57
|
import { auditMemories, appendAuditEvent, } from './audit.js';
|
|
56
58
|
import { listApiKeys, revokeApiKey } from './auth.js';
|
|
@@ -1482,9 +1484,15 @@ async function cmdRecall(hippoRoot, query, flags) {
|
|
|
1482
1484
|
// Update retrieval metadata and persist
|
|
1483
1485
|
const updated = markRetrieved(results.map((r) => r.entry));
|
|
1484
1486
|
const localIndex = loadIndex(hippoRoot);
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1487
|
+
// EVAL-ONLY ablation (see ablation.ts): under the recall flag, markRetrieved
|
|
1488
|
+
// returns unmutated entries (ids preserved for outcome attribution below)
|
|
1489
|
+
// and persistence is skipped - writeEntry on identical rows still refreshes
|
|
1490
|
+
// updated_at, rewrites mirrors, and marks DAG parents dirty.
|
|
1491
|
+
if (!isRecallBoostAblated()) {
|
|
1492
|
+
for (const u of updated) {
|
|
1493
|
+
const targetRoot = localIndex.entries[u.id] ? hippoRoot : (isInitialized(globalRoot) ? globalRoot : hippoRoot);
|
|
1494
|
+
writeEntry(targetRoot, u);
|
|
1495
|
+
}
|
|
1488
1496
|
}
|
|
1489
1497
|
// Track last retrieval IDs for outcome command
|
|
1490
1498
|
localIndex.last_retrieval_ids = updated.map((u) => u.id);
|
|
@@ -2091,7 +2099,7 @@ function cmdTrace(hippoRoot, id, flags) {
|
|
|
2091
2099
|
console.error(`Memory not found: ${id}`);
|
|
2092
2100
|
process.exit(1);
|
|
2093
2101
|
}
|
|
2094
|
-
const now =
|
|
2102
|
+
const now = evalNow();
|
|
2095
2103
|
const strength = calculateStrength(entry, now);
|
|
2096
2104
|
const halfLife = deriveHalfLife(7, entry);
|
|
2097
2105
|
const rewardFactor = calculateRewardFactor(entry);
|
|
@@ -2705,7 +2713,7 @@ function cmdStatus(hippoRoot) {
|
|
|
2705
2713
|
requireInit(hippoRoot);
|
|
2706
2714
|
const entries = loadAllEntries(hippoRoot);
|
|
2707
2715
|
const stats = loadStats(hippoRoot);
|
|
2708
|
-
const now =
|
|
2716
|
+
const now = evalNow();
|
|
2709
2717
|
const byLayer = {
|
|
2710
2718
|
[Layer.Buffer]: 0,
|
|
2711
2719
|
[Layer.Episodic]: 0,
|
|
@@ -2926,7 +2934,7 @@ function cmdInspect(hippoRoot, id) {
|
|
|
2926
2934
|
console.error(`Memory not found: ${id}`);
|
|
2927
2935
|
process.exit(1);
|
|
2928
2936
|
}
|
|
2929
|
-
const now =
|
|
2937
|
+
const now = evalNow();
|
|
2930
2938
|
const currentStrength = calculateStrength(entry, now);
|
|
2931
2939
|
const lastRetrieved = new Date(entry.last_retrieved);
|
|
2932
2940
|
const created = new Date(entry.created);
|
|
@@ -4911,6 +4919,9 @@ async function cmdContext(hippoRoot, args, flags) {
|
|
|
4911
4919
|
tenantId: resolveTenantId({}),
|
|
4912
4920
|
actor: api.adminActor('cli'),
|
|
4913
4921
|
};
|
|
4922
|
+
// v39 memory scope isolation: --cross-project re-includes other-project
|
|
4923
|
+
// memories (rendered under a demarcated section below).
|
|
4924
|
+
const crossProject = flags['cross-project'] === true;
|
|
4914
4925
|
const opts = {
|
|
4915
4926
|
q: query,
|
|
4916
4927
|
budget,
|
|
@@ -4918,6 +4929,7 @@ async function cmdContext(hippoRoot, args, flags) {
|
|
|
4918
4929
|
pinnedOnly,
|
|
4919
4930
|
scope: ctxActiveScope ?? undefined,
|
|
4920
4931
|
includeRecent: parseCountFlag(flags['include-recent']),
|
|
4932
|
+
crossProject,
|
|
4921
4933
|
};
|
|
4922
4934
|
const result = await api.getContext(ctx, opts);
|
|
4923
4935
|
// Early exit when there's nothing to render (matches pre-extraction behavior).
|
|
@@ -4930,8 +4942,13 @@ async function cmdContext(hippoRoot, args, flags) {
|
|
|
4930
4942
|
// Format + framing are CLI rendering concerns; api.getContext doesn't see them.
|
|
4931
4943
|
const format = String(flags['format'] ?? 'markdown');
|
|
4932
4944
|
const framing = String(flags['framing'] ?? 'observe');
|
|
4933
|
-
// Adapter: ContextResultEntry -> the print-helper input shape.
|
|
4934
|
-
|
|
4945
|
+
// Adapter: ContextResultEntry -> the print-helper input shape. v39:
|
|
4946
|
+
// cross-project inclusions (only present under --cross-project or with
|
|
4947
|
+
// isolation disabled via crossProject) render in their own demarcated
|
|
4948
|
+
// section so they can never masquerade as project memory.
|
|
4949
|
+
const mainEntries = result.entries.filter((r) => r.category !== 'cross-project');
|
|
4950
|
+
const crossEntries = result.entries.filter((r) => r.category === 'cross-project');
|
|
4951
|
+
const renderItems = mainEntries.map((r) => ({
|
|
4935
4952
|
entry: r.entry,
|
|
4936
4953
|
score: r.score,
|
|
4937
4954
|
tokens: r.tokens,
|
|
@@ -4946,6 +4963,8 @@ async function cmdContext(hippoRoot, args, flags) {
|
|
|
4946
4963
|
confidence: r.entry.confidence,
|
|
4947
4964
|
content: r.entry.content,
|
|
4948
4965
|
global: r.isGlobal ?? false,
|
|
4966
|
+
origin: r.origin ?? null,
|
|
4967
|
+
category: r.category ?? null,
|
|
4949
4968
|
}));
|
|
4950
4969
|
console.log(JSON.stringify({
|
|
4951
4970
|
query: query || '*',
|
|
@@ -4973,6 +4992,7 @@ async function cmdContext(hippoRoot, args, flags) {
|
|
|
4973
4992
|
if (renderItems.length > 0) {
|
|
4974
4993
|
printContextMarkdown(renderItems, result.tokens, framing);
|
|
4975
4994
|
}
|
|
4995
|
+
printCrossProjectSection(crossEntries);
|
|
4976
4996
|
}
|
|
4977
4997
|
finally {
|
|
4978
4998
|
console.log = realLog;
|
|
@@ -5002,6 +5022,7 @@ async function cmdContext(hippoRoot, args, flags) {
|
|
|
5002
5022
|
if (renderItems.length > 0) {
|
|
5003
5023
|
printContextMarkdown(renderItems, result.tokens, framing);
|
|
5004
5024
|
}
|
|
5025
|
+
printCrossProjectSection(crossEntries);
|
|
5005
5026
|
// Ambient state summary (CLI-side: api.getContext doesn't load all entries
|
|
5006
5027
|
// post-selection, so we re-load here for the landscape summary).
|
|
5007
5028
|
const ambientConfig = loadConfig(hippoRoot);
|
|
@@ -5009,11 +5030,17 @@ async function cmdContext(hippoRoot, args, flags) {
|
|
|
5009
5030
|
const tenantId = ctx.tenantId;
|
|
5010
5031
|
const globalRoot = getGlobalRoot();
|
|
5011
5032
|
const hasGlobalForAmbient = isInitialized(globalRoot);
|
|
5033
|
+
// v39: the landscape summary must reflect the same admission policy as
|
|
5034
|
+
// the injected entries - otherwise excluded rows leak back in as
|
|
5035
|
+
// aggregate signal (codex P2-13).
|
|
5036
|
+
const isolationOff = ambientConfig.contextProjectIsolation === false;
|
|
5037
|
+
const ambientCurrentName = resolveProjectIdentity(process.cwd()).name;
|
|
5038
|
+
const ambientAdmit = (e) => api.ambientAdmitEntry(e, ambientCurrentName, crossProject || isolationOff);
|
|
5012
5039
|
const localForAmbient = isInitialized(hippoRoot)
|
|
5013
|
-
? loadAllEntries(hippoRoot, tenantId).filter(e => !e.superseded_by)
|
|
5040
|
+
? loadAllEntries(hippoRoot, tenantId).filter(e => !e.superseded_by).filter(ambientAdmit)
|
|
5014
5041
|
: [];
|
|
5015
5042
|
const globalForAmbient = hasGlobalForAmbient
|
|
5016
|
-
? loadAllEntries(globalRoot, tenantId).filter(e => !e.superseded_by)
|
|
5043
|
+
? loadAllEntries(globalRoot, tenantId).filter(e => !e.superseded_by).filter(ambientAdmit)
|
|
5017
5044
|
: [];
|
|
5018
5045
|
const allForAmbient = [...localForAmbient, ...globalForAmbient];
|
|
5019
5046
|
if (allForAmbient.length > 0) {
|
|
@@ -5023,9 +5050,24 @@ async function cmdContext(hippoRoot, args, flags) {
|
|
|
5023
5050
|
}
|
|
5024
5051
|
}
|
|
5025
5052
|
}
|
|
5053
|
+
/**
|
|
5054
|
+
* v39: render cross-project inclusions under an explicit header so agents
|
|
5055
|
+
* (and humans) can tell borrowed context from project memory. Only ever
|
|
5056
|
+
* non-empty when the caller passed --cross-project or disabled isolation.
|
|
5057
|
+
*/
|
|
5058
|
+
function printCrossProjectSection(items) {
|
|
5059
|
+
if (items.length === 0)
|
|
5060
|
+
return;
|
|
5061
|
+
console.log(`\n## Other-project memory (explicitly requested, ${items.length} entries)\n`);
|
|
5062
|
+
for (const item of items) {
|
|
5063
|
+
const originLabel = item.origin === null || item.origin === '' ? 'unknown-origin' : item.origin;
|
|
5064
|
+
const tagStr = item.entry.tags.length > 0 ? ` [${item.entry.tags.join(', ')}]` : '';
|
|
5065
|
+
console.log(`- **[${originLabel}]** ${item.entry.content}${tagStr}`);
|
|
5066
|
+
}
|
|
5067
|
+
}
|
|
5026
5068
|
/** @internal — exported for snapshot tests (tests/cli-context-render-snapshot.test.ts). NOT a stable public API. */
|
|
5027
5069
|
export function printContextMarkdown(items, totalTokens, framing = 'observe') {
|
|
5028
|
-
const now =
|
|
5070
|
+
const now = evalNow();
|
|
5029
5071
|
console.log(`## Project Memory (${items.length} entries, ${totalTokens} tokens)\n`);
|
|
5030
5072
|
for (const item of items) {
|
|
5031
5073
|
const e = item.entry;
|
|
@@ -5320,6 +5362,54 @@ function cmdImport(hippoRoot, args, flags) {
|
|
|
5320
5362
|
extraTags,
|
|
5321
5363
|
hippoRoot,
|
|
5322
5364
|
};
|
|
5365
|
+
// K1 vault import: a FOLDER importer that mirrors the connector pattern
|
|
5366
|
+
// (kind='raw' + tag provenance + archiveRaw deletions), so it dispatches
|
|
5367
|
+
// separately from the single-file `importer` function-pointer slot below.
|
|
5368
|
+
// It writes through api.remember/archiveRaw which are tenant-scoped, so we
|
|
5369
|
+
// resolve the tenant and pass it through. --global is not supported for
|
|
5370
|
+
// vault import (the connector raw-archive path is tenant-local).
|
|
5371
|
+
if (flags['vault']) {
|
|
5372
|
+
const folderPath = String(flags['vault']);
|
|
5373
|
+
if (!fs.existsSync(folderPath) || !fs.statSync(folderPath).isDirectory()) {
|
|
5374
|
+
console.error(`Vault folder not found (or not a directory): ${folderPath}`);
|
|
5375
|
+
process.exit(1);
|
|
5376
|
+
}
|
|
5377
|
+
if (useGlobal) {
|
|
5378
|
+
console.error('hippo import --vault does not support --global (raw rows are tenant-local).');
|
|
5379
|
+
process.exit(1);
|
|
5380
|
+
}
|
|
5381
|
+
if (typeof flags['name'] !== 'string' || !flags['name'].trim()) {
|
|
5382
|
+
// --name is the vault identity key for the destructive source-deletion sync;
|
|
5383
|
+
// inferring it from the folder basename let same-basename vaults collide and
|
|
5384
|
+
// clobber each other (codex R10 P2). A valueless `--name` parses as boolean
|
|
5385
|
+
// true, and String(true) === "true" would silently import under vault:true:*
|
|
5386
|
+
// - reject a non-string so it fails fast instead (codex R11 P2).
|
|
5387
|
+
console.error('hippo import --vault requires --name <vault> (a non-empty identity key for source-deletion sync).');
|
|
5388
|
+
process.exit(1);
|
|
5389
|
+
}
|
|
5390
|
+
if (flags['scope'] !== undefined && (typeof flags['scope'] !== 'string' || !flags['scope'].trim())) {
|
|
5391
|
+
// Same valueless-flag trap: a bare `--scope` must not become scope "true".
|
|
5392
|
+
// Example uses the source-prefixed private form, since a bare `private` scope
|
|
5393
|
+
// is NOT treated as private by recall and importVault rejects it (R13 P2).
|
|
5394
|
+
console.error('hippo import --vault: --scope requires a value (e.g. --scope vault:private:notes).');
|
|
5395
|
+
process.exit(1);
|
|
5396
|
+
}
|
|
5397
|
+
const tenantId = resolveTenantId({});
|
|
5398
|
+
const vaultOptions = {
|
|
5399
|
+
...importOptions,
|
|
5400
|
+
tenantId,
|
|
5401
|
+
name: flags['name'] ? String(flags['name']) : undefined,
|
|
5402
|
+
scope: flags['scope'] ? String(flags['scope']) : undefined,
|
|
5403
|
+
};
|
|
5404
|
+
const vaultResult = importVault(folderPath, vaultOptions);
|
|
5405
|
+
console.log(`\nImport Vault: ${folderPath}${dryRun ? ' (dry run - no writes)' : ''}`);
|
|
5406
|
+
console.log(` Notes found: ${vaultResult.total}`);
|
|
5407
|
+
console.log(` ${dryRun ? 'Would import: ' : 'Imported: '}${vaultResult.imported}`);
|
|
5408
|
+
console.log(` Skipped (unchanged): ${vaultResult.skipped}`);
|
|
5409
|
+
console.log(` ${dryRun ? 'Would archive: ' : 'Archived (removed): '}${vaultResult.archived ?? 0}`);
|
|
5410
|
+
console.log(` Store: ${hippoRoot}`);
|
|
5411
|
+
return;
|
|
5412
|
+
}
|
|
5323
5413
|
// Determine which importer to use based on flag
|
|
5324
5414
|
let filePath;
|
|
5325
5415
|
let importer;
|
|
@@ -5356,7 +5446,7 @@ function cmdImport(hippoRoot, args, flags) {
|
|
|
5356
5446
|
importerName = 'File';
|
|
5357
5447
|
}
|
|
5358
5448
|
if (!filePath || !importer) {
|
|
5359
|
-
console.error('Usage: hippo import <--chatgpt|--claude|--cursor|--file|--markdown> <path>');
|
|
5449
|
+
console.error('Usage: hippo import <--chatgpt|--claude|--cursor|--file|--markdown|--vault> <path>');
|
|
5360
5450
|
process.exit(1);
|
|
5361
5451
|
}
|
|
5362
5452
|
if (!fs.existsSync(filePath)) {
|
|
@@ -5412,15 +5502,17 @@ function cmdPromote(hippoRoot, id) {
|
|
|
5412
5502
|
// ---------------------------------------------------------------------------
|
|
5413
5503
|
// Sync command
|
|
5414
5504
|
// ---------------------------------------------------------------------------
|
|
5415
|
-
function cmdSync(hippoRoot) {
|
|
5505
|
+
function cmdSync(hippoRoot, flags = {}) {
|
|
5416
5506
|
requireInit(hippoRoot);
|
|
5417
5507
|
const globalRoot = getGlobalRoot();
|
|
5418
5508
|
if (!isInitialized(globalRoot)) {
|
|
5419
5509
|
console.log('No global store found. Run `hippo init --global` first.');
|
|
5420
5510
|
return;
|
|
5421
5511
|
}
|
|
5422
|
-
|
|
5423
|
-
|
|
5512
|
+
// v39: other-project rows are skipped by default; secrets always are.
|
|
5513
|
+
const includeCrossProject = flags['cross-project'] === true;
|
|
5514
|
+
const count = syncGlobalToLocal(hippoRoot, globalRoot, { includeCrossProject });
|
|
5515
|
+
console.log(`Synced ${count} global memories into local project.${includeCrossProject ? '' : ' (other-project rows skipped; use --cross-project to include them)'}`);
|
|
5424
5516
|
}
|
|
5425
5517
|
// ---------------------------------------------------------------------------
|
|
5426
5518
|
// Hook install/uninstall
|
|
@@ -5436,7 +5528,11 @@ const HOOKS = {
|
|
|
5436
5528
|
content: `
|
|
5437
5529
|
## Project Memory (Hippo)
|
|
5438
5530
|
|
|
5439
|
-
|
|
5531
|
+
Pinned rules and recent writes auto-inject at every prompt via the installed
|
|
5532
|
+
UserPromptSubmit hook; never re-run that part manually. At the START of a
|
|
5533
|
+
task (not per prompt), additionally load task-specific context: git-aware
|
|
5534
|
+
recall over the full store that per-prompt injection does not cover. Also
|
|
5535
|
+
run it if the hook is not installed:
|
|
5440
5536
|
\`\`\`bash
|
|
5441
5537
|
hippo context --auto --budget 1500
|
|
5442
5538
|
\`\`\`
|
|
@@ -7076,6 +7172,9 @@ Commands:
|
|
|
7076
7172
|
--cursor <path> Import from .cursorrules or .cursor/rules
|
|
7077
7173
|
--file <path> Import from any markdown or text file
|
|
7078
7174
|
--markdown <path> Import from structured MEMORY.md / AGENTS.md
|
|
7175
|
+
--vault <path> Import a markdown-vault FOLDER as kind='raw' notes
|
|
7176
|
+
(Obsidian/Foam/Dendron). Requires --name <vault>.
|
|
7177
|
+
[--scope <scope>]
|
|
7079
7178
|
--dry-run Preview without writing
|
|
7080
7179
|
--global Write to global store ($HIPPO_HOME or ~/.hippo/)
|
|
7081
7180
|
--tag <tag> Add extra tag (repeatable)
|
|
@@ -7670,7 +7769,7 @@ async function main() {
|
|
|
7670
7769
|
break;
|
|
7671
7770
|
}
|
|
7672
7771
|
case 'sync':
|
|
7673
|
-
cmdSync(hippoRoot);
|
|
7772
|
+
cmdSync(hippoRoot, flags);
|
|
7674
7773
|
break;
|
|
7675
7774
|
case 'share': {
|
|
7676
7775
|
const shareId = args[0];
|