Files
Hy-Memory/memhub/apps/cli/src/graph-width-flow.ts
T
alvinfeiandClaude Opus 5.5 072e0e5e90 feat(memhub): simplify the CLI and drop the notes concept
API: adding one memory is POST /api/v2/memories with its status at
GET /api/v2/memories/additions/{request_id}; /api/v1/memory-notes is
removed. Error codes memory_note_* become memory_add_*, contracts types
MemoryAddInput/MemoryAddReceipt, broker /memories, MCP MemHub_write and
the web composer follow. Stored names (memory_note_requests,
one-memory-manual, direct_memory_note) stay. /api/v2/memory-library
takes an optional scene filter.

CLI:
- No plan files. memories add/add-status, models add/test/receipt and
  sources connect execute directly; async receipts stay.
- One --yes, only for irreversible operations (memories delete, models
  remove, delete-data, backup restore, graph-width rebuild); without it
  they preview and exit 0. --confirm is a hidden alias.
- Removed notes, calls, setup plan, sources import, models
  plan/configure/probe*, and the unreachable processing, extraction and
  import-file commands, with their dead allow-list entries.
- memories list gets --scene/--source/--query; show/update/delete take
  --kind/--variant (and --task). All memories JSON is schema_version 2.
- Fixes from the CLI review: global --data-dir, real
  --confirm-overrides and help that matches init, server failures exit 1
  not 2, catalog exit codes match, JSON errors on stdout, bad filters are
  rejected instead of "busy", write submit prints its request_id for
  retries, recall labels raw excerpts, stop says it disables login
  auto-start, backup help says memories are not included yet.
- Hidden aliases: path -> scan-roots, task -> write status,
  graph width -> graph-width, init --source -> sources connect.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-27 19:21:34 +08:00

94 lines
2.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* `memhub graph-width`: the user's decision when the embedding width changed
* and the memory graph no longer matches it (`POST /api/v1/graph-width`).
*
* `keep_existing` and `export_first` change nothing irreversible and run
* directly. `rebuild_with_new` archives the current graph and rebuilds it, so
* the CLI asks for `--yes` before sending it.
*/
import { parseGraphWidthDecisionReceipt } from "@one-memory/operations";
import type { CoreOperations } from "./core-operations.js";
import { PRODUCT } from "./version.js";
export const GRAPH_WIDTH_DECISIONS = [
"keep_existing",
"rebuild_with_new",
"export_first",
] as const;
export type GraphWidthDecision = (typeof GRAPH_WIDTH_DECISIONS)[number];
/** The one decision that cannot be taken back. */
export function graphWidthDecisionIsDestructive(
decision: GraphWidthDecision,
): boolean {
return decision === "rebuild_with_new";
}
export type GraphWidthDocument =
| {
schema_version: 1;
product: string;
command: "graph-width";
state: "committed";
decision: GraphWidthDecision;
receipt: Record<string, unknown>;
}
| {
schema_version: 1;
product: string;
command: "graph-width";
state: "rejected" | "unknown";
decision: GraphWidthDecision;
code: string;
};
export async function decideGraphWidth(
decision: GraphWidthDecision,
operations: CoreOperations,
): Promise<GraphWidthDocument> {
const base = {
schema_version: 1 as const,
product: PRODUCT,
command: "graph-width" as const,
decision,
};
const result = await operations.post<unknown>("/api/v1/graph-width", {
decision,
});
if (result.state !== "committed") {
return { ...base, state: result.state, code: result.code };
}
const receipt = parseGraphWidthDecisionReceipt(result.data);
if (receipt === null) {
return { ...base, state: "unknown", code: "graph_width_receipt_invalid" };
}
return {
...base,
state: "committed",
receipt: {
archived_path: receipt.archived_path ?? null,
exported_path: receipt.exported_path ?? null,
mismatch: receipt.mismatch ?? null,
},
};
}
export function graphWidthExitCode(document: GraphWidthDocument): number {
return document.state === "committed" ? 0 : 1;
}
export function renderGraphWidthText(document: GraphWidthDocument): string {
if (document.state === "committed") {
const lines = [`已执行图谱宽度决定:${document.decision}`];
if (document.receipt.exported_path) {
lines.push(`导出:${document.receipt.exported_path}`);
}
if (document.receipt.archived_path) {
lines.push(`旧图谱已归档:${document.receipt.archived_path}`);
}
return `${lines.join("\n")}\n`;
}
return `图谱宽度决定未完成:${document.state}(${document.code})\n`;
}