@oortmem/core 0.5.0 → 0.5.2

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.
@@ -218,6 +218,43 @@ export interface DecisionController {
218
218
  obs: Observation;
219
219
  candidates: Memory[];
220
220
  }[]): Promise<ReconcileDecision[][]>;
221
+ /**
222
+ * Judgment memory (CON-71): which verdict the expert behind `req.precedents` would most likely
223
+ * give `req.item`, as a choice over `req.verdicts` with a probability per verdict. Optional; a
224
+ * controller without it leaves judging at precedents only.
225
+ */
226
+ judge?(req: JudgeRequest): Promise<JudgeChoice>;
227
+ }
228
+ /** One past decision as the controller sees it: the expert's reason verbatim. */
229
+ export interface JudgePrecedent {
230
+ subject: string;
231
+ ref?: string;
232
+ verdict: string;
233
+ reason: string;
234
+ criteria: string[];
235
+ decidedAt: string;
236
+ /** How close it is to the item, 0 to 1 (dense cosine, or lexical overlap). */
237
+ similarity: number;
238
+ }
239
+ /** What `DecisionController.judge` is asked. */
240
+ export interface JudgeRequest {
241
+ item: {
242
+ summary: string;
243
+ details?: string;
244
+ ref?: string;
245
+ domain?: string;
246
+ };
247
+ /** The verdicts to choose from; the precedents' own verdicts are among them. */
248
+ verdicts: string[];
249
+ /** Nearest first. Never empty. */
250
+ precedents: JudgePrecedent[];
251
+ }
252
+ /** The controller's answer: the likeliest verdict, its probability, and every verdict's. */
253
+ export interface JudgeChoice {
254
+ verdict: string;
255
+ probability: number;
256
+ probabilities: Record<string, number>;
257
+ decisions: Decision[];
221
258
  }
222
259
  /** One memory as the writer authors it. */
223
260
  export interface WrittenMemory {
package/dist/config.d.ts CHANGED
@@ -43,17 +43,36 @@ export declare const OortConfig: z.ZodObject<{
43
43
  queryCacheTtlSec: z.ZodDefault<z.ZodNumber>;
44
44
  staleAfterDays: z.ZodDefault<z.ZodNumber>;
45
45
  specificityPrior: z.ZodDefault<z.ZodNumber>;
46
+ promptMode: z.ZodDefault<z.ZodEnum<{
47
+ fast: "fast";
48
+ full: "full";
49
+ lexical: "lexical";
50
+ }>>;
46
51
  }, z.core.$strict>>;
47
52
  project: z.ZodDefault<z.ZodObject<{
48
53
  id: z.ZodOptional<z.ZodString>;
49
54
  private: z.ZodDefault<z.ZodBoolean>;
50
55
  }, z.core.$strict>>;
56
+ serve: z.ZodDefault<z.ZodObject<{
57
+ autostart: z.ZodDefault<z.ZodBoolean>;
58
+ idleMinutes: z.ZodDefault<z.ZodNumber>;
59
+ }, z.core.$strict>>;
60
+ judge: z.ZodDefault<z.ZodObject<{
61
+ experts: z.ZodDefault<z.ZodArray<z.ZodString>>;
62
+ operator: z.ZodOptional<z.ZodString>;
63
+ }, z.core.$strict>>;
51
64
  }, z.core.$strict>;
52
65
  export type OortConfig = z.infer<typeof OortConfig>;
53
66
  export type ConfigSource = 'project' | 'home' | 'default';
54
67
  export type ResolvedConfig = OortConfig & {
55
68
  home: string;
56
69
  sources: Record<string, ConfigSource>;
70
+ /**
71
+ * Keys a project's `oort.config.json` set that only the home config may set (`serve`: a
72
+ * repository must not start processes on this machine; `judge`: nor name experts). Ignored;
73
+ * absent when there are none.
74
+ */
75
+ ignoredProjectKeys?: string[];
57
76
  };
58
77
  /**
59
78
  * Oort's home directory, always absolute: `OORT_HOME` resolved against the
package/dist/config.js CHANGED
@@ -75,6 +75,13 @@ const recall = z
75
75
  * Galaxy 0). 0, the default, turns it off: it is turned on only if the eval shows a gain.
76
76
  */
77
77
  specificityPrior: z.number().min(0).max(1).default(0),
78
+ /**
79
+ * How the prompt hook (Claude Code's UserPromptSubmit) recalls, locally and in Oort Cloud
80
+ * (CON-101): `full` embeds the prompt and reranks; `fast` skips the reranker (fusion and the
81
+ * relevance gate rank); `lexical` skips the query embedding too (no model call at all). `oort
82
+ * recall`, MCP and SessionStart always recall in full.
83
+ */
84
+ promptMode: z.enum(['full', 'fast', 'lexical']).default('full'),
78
85
  })
79
86
  .default({
80
87
  lexicalK: 50,
@@ -91,6 +98,7 @@ const recall = z
91
98
  queryCacheTtlSec: 600,
92
99
  staleAfterDays: 30,
93
100
  specificityPrior: 0,
101
+ promptMode: 'full',
94
102
  });
95
103
  const project = z
96
104
  .strictObject({
@@ -99,6 +107,32 @@ const project = z
99
107
  private: z.boolean().default(false),
100
108
  })
101
109
  .default({ private: false });
110
+ /**
111
+ * `oort serve`, the local daemon the hooks talk to (CON-18). Read from the home config only: a
112
+ * repository's `oort.config.json` cannot start processes on this machine.
113
+ */
114
+ const serve = z
115
+ .strictObject({
116
+ /** SessionStart starts a detached daemon when none is running. */
117
+ autostart: z.boolean().default(false),
118
+ /** The daemon exits after this many minutes without a hook request. */
119
+ idleMinutes: z.number().int().min(1).max(1440).default(30),
120
+ })
121
+ .default({ autostart: false, idleMinutes: 30 });
122
+ /**
123
+ * Judgment memory (CON-71). Read from the home config only: a repository's `oort.config.json`
124
+ * cannot name who counts as an expert.
125
+ * - `experts`: the expert ids an agent may record judgments for over MCP (`record_judgment`).
126
+ * Empty (the default): MCP recording is refused.
127
+ * - `operator`: who withdraws, confirms or purges judgments from this machine (`--by` overrides);
128
+ * default `local-user`.
129
+ */
130
+ const judge = z
131
+ .strictObject({
132
+ experts: z.array(z.string().trim().min(1).max(128)).max(200).default([]),
133
+ operator: z.string().trim().min(1).max(128).optional(),
134
+ })
135
+ .default({ experts: [] });
102
136
  export const OortConfig = z.strictObject({
103
137
  embed,
104
138
  rerank,
@@ -107,7 +141,11 @@ export const OortConfig = z.strictObject({
107
141
  activation,
108
142
  recall,
109
143
  project,
144
+ serve,
145
+ judge,
110
146
  });
147
+ /** Keys read from the home config only; a project file's value is ignored (and reported). */
148
+ const HOME_ONLY_KEYS = new Set(['serve', 'judge']);
111
149
  const CONFIG_KEYS = Object.keys(OortConfig.shape);
112
150
  function findProjectConfig(cwd) {
113
151
  let dir = path.resolve(cwd);
@@ -175,8 +213,11 @@ export function resolveConfig(cwd, env = process.env, opts = {}) {
175
213
  const homeRaw = fs.existsSync(homeFile) ? readConfigFile(homeFile) : {};
176
214
  const merged = {};
177
215
  const sources = {};
216
+ const ignored = [];
178
217
  for (const key of CONFIG_KEYS) {
179
- if (key in projectRaw) {
218
+ if (key in projectRaw && HOME_ONLY_KEYS.has(key))
219
+ ignored.push(key);
220
+ if (key in projectRaw && !HOME_ONLY_KEYS.has(key)) {
180
221
  merged[key] = projectRaw[key];
181
222
  sources[key] = 'project';
182
223
  }
@@ -188,6 +229,11 @@ export function resolveConfig(cwd, env = process.env, opts = {}) {
188
229
  sources[key] = 'default';
189
230
  }
190
231
  }
191
- return { ...OortConfig.parse(merged), home, sources };
232
+ return {
233
+ ...OortConfig.parse(merged),
234
+ home,
235
+ sources,
236
+ ...(ignored.length > 0 && { ignoredProjectKeys: ignored }),
237
+ };
192
238
  }
193
239
  //# sourceMappingURL=config.js.map
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Characters that must never reach a terminal or a person deciding something as they are: C0 and
3
+ * C1 controls, the bidi controls (Trojan Source) and zero-width or other invisible format
4
+ * characters. One source for the CLI's `shown()`/`safeJson()` and for judgment memory's input
5
+ * checks (CON-71), so the two never drift. Written as escapes: no literal one sits in this file.
6
+ */
7
+ export declare const DISPLAY_UNSAFE_SOURCE = "[\\u0000-\\u001f\\u007f-\\u009f\\u061c\\u200b-\\u200f\\u202a-\\u202e\\u2060-\\u2064\\u2066-\\u2069\\ufeff]";
8
+ /** DISPLAY_UNSAFE_SOURCE without C0 and C1: the bidi and invisible format characters alone. */
9
+ export declare const INVISIBLE_SOURCE = "[\\u061c\\u200b-\\u200f\\u202a-\\u202e\\u2060-\\u2064\\u2066-\\u2069\\ufeff]";
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Characters that must never reach a terminal or a person deciding something as they are: C0 and
3
+ * C1 controls, the bidi controls (Trojan Source) and zero-width or other invisible format
4
+ * characters. One source for the CLI's `shown()`/`safeJson()` and for judgment memory's input
5
+ * checks (CON-71), so the two never drift. Written as escapes: no literal one sits in this file.
6
+ */
7
+ export const DISPLAY_UNSAFE_SOURCE = '[\\u0000-\\u001f\\u007f-\\u009f\\u061c\\u200b-\\u200f\\u202a-\\u202e\\u2060-\\u2064\\u2066-\\u2069\\ufeff]';
8
+ /** DISPLAY_UNSAFE_SOURCE without C0 and C1: the bidi and invisible format characters alone. */
9
+ export const INVISIBLE_SOURCE = '[\\u061c\\u200b-\\u200f\\u202a-\\u202e\\u2060-\\u2064\\u2066-\\u2069\\ufeff]';
10
+ //# sourceMappingURL=display.js.map
@@ -38,7 +38,10 @@ export interface HiddenLinkFlags {
38
38
  export declare class ExportFormatError extends Error {
39
39
  constructor(message: string);
40
40
  }
41
- /** True when version 1 can hold `m`: a Planet memory whose author is its scope's agent. */
41
+ /**
42
+ * True when version 1 can hold `m`: a Planet memory whose author is its scope's agent, and not a
43
+ * judgment (CON-71; version 1 readers know four memory types and no `judgment` field).
44
+ */
42
45
  export declare function fitsVersion1(m: Memory): boolean;
43
46
  /**
44
47
  * One memory as an export line of `version`: the embedding as base64 of its
@@ -16,10 +16,15 @@ export class ExportFormatError extends Error {
16
16
  }
17
17
  }
18
18
  const base64 = (v) => Buffer.from(v.buffer, v.byteOffset, v.byteLength).toString('base64');
19
- /** True when version 1 can hold `m`: a Planet memory whose author is its scope's agent. */
19
+ /**
20
+ * True when version 1 can hold `m`: a Planet memory whose author is its scope's agent, and not a
21
+ * judgment (CON-71; version 1 readers know four memory types and no `judgment` field).
22
+ */
20
23
  export function fitsVersion1(m) {
21
24
  const author = authorOf(m);
22
- return (addressOf(m).level === 'user' &&
25
+ return (m.type !== 'judgment' &&
26
+ m.judgment === undefined &&
27
+ addressOf(m).level === 'user' &&
23
28
  author.accountRef === undefined &&
24
29
  author.agentId === m.scope.agentId &&
25
30
  (m.provenance === undefined || m.provenance === null));
package/dist/fusion.d.ts CHANGED
@@ -9,6 +9,8 @@ export interface TemporalView {
9
9
  asOf?: string;
10
10
  /** For `known-at`: the instant in transaction time. */
11
11
  knownAt?: string;
12
+ /** Also show withdrawn judgments (CON-71); every mode leaves them out by default. */
13
+ includeWithdrawn?: boolean;
12
14
  }
13
15
  /**
14
16
  * Weight of the activation boost: fused = rrf * (1 + ACTIVATION_BOOST * sigmoid(A)). With one RRF
package/dist/fusion.js CHANGED
@@ -54,6 +54,9 @@ const t = (iso) => Date.parse(iso);
54
54
  * - history: every version of a fact, except corrected ones.
55
55
  */
56
56
  export function isVisible(m, now, v) {
57
+ // A withdrawn judgment no longer counts in any slice of time: the expert took it back.
58
+ if (m.judgment?.withdrawn !== undefined && v.includeWithdrawn !== true)
59
+ return false;
57
60
  switch (v.mode) {
58
61
  case 'current':
59
62
  return isCurrent(m, now);
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export declare const VERSION = "0.5.0";
1
+ export declare const VERSION = "0.5.2";
2
2
  export * from './model.js';
3
3
  export * from './address.js';
4
4
  export * from './export-format.js';
@@ -25,3 +25,5 @@ export * from './cap.js';
25
25
  export * from './consolidate.js';
26
26
  export * from './errors.js';
27
27
  export * from './private-fs.js';
28
+ export * from './judgment.js';
29
+ export * from './display.js';
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export const VERSION = '0.5.0';
1
+ export const VERSION = '0.5.2';
2
2
  export * from './model.js';
3
3
  export * from './address.js';
4
4
  export * from './export-format.js';
@@ -25,4 +25,6 @@ export * from './cap.js';
25
25
  export * from './consolidate.js';
26
26
  export * from './errors.js';
27
27
  export * from './private-fs.js';
28
+ export * from './judgment.js';
29
+ export * from './display.js';
28
30
  //# sourceMappingURL=index.js.map