@ouro.bot/cli 0.1.0-alpha.657 → 0.1.0-alpha.658

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.
Files changed (52) hide show
  1. package/README.md +13 -13
  2. package/changelog.json +9 -0
  3. package/dist/arc/evolution.js +1 -1
  4. package/dist/arc/flight-recorder.js +369 -0
  5. package/dist/arc/obligations.js +24 -2
  6. package/dist/heart/active-work.js +1 -1
  7. package/dist/heart/config-registry.js +5 -5
  8. package/dist/heart/daemon/agent-config-check.js +1 -1
  9. package/dist/heart/daemon/agent-service.js +18 -17
  10. package/dist/heart/daemon/cli-exec.js +27 -12
  11. package/dist/heart/daemon/cli-help.js +14 -0
  12. package/dist/heart/daemon/cli-parse.js +26 -0
  13. package/dist/heart/daemon/daemon-entry.js +1 -1
  14. package/dist/heart/daemon/daemon.js +3 -3
  15. package/dist/heart/daemon/hooks/bundle-meta.js +29 -9
  16. package/dist/heart/daemon/inner-status.js +4 -15
  17. package/dist/heart/habits/habit-parser.js +64 -1
  18. package/dist/heart/hatch/hatch-flow.js +17 -9
  19. package/dist/heart/hatch/specialist-tools.js +15 -11
  20. package/dist/heart/kept-notes.js +5 -73
  21. package/dist/heart/mailbox/readers/runtime-readers.js +21 -49
  22. package/dist/heart/mcp/mcp-server.js +8 -8
  23. package/dist/heart/session-events.js +1 -31
  24. package/dist/heart/start-of-turn-packet.js +8 -2
  25. package/dist/heart/tool-description.js +15 -3
  26. package/dist/heart/turn-context.js +27 -7
  27. package/dist/heart/work-card.js +386 -0
  28. package/dist/mailbox-ui/assets/{index-9-AxCxuB.js → index-Cbasiy6y.js} +1 -1
  29. package/dist/mailbox-ui/index.html +1 -1
  30. package/dist/mind/bundle-manifest.js +9 -3
  31. package/dist/mind/context.js +1 -2
  32. package/dist/mind/desk-section.js +53 -1
  33. package/dist/mind/diary.js +2 -3
  34. package/dist/mind/note-search.js +36 -106
  35. package/dist/mind/prompt.js +37 -102
  36. package/dist/mind/record-paths.js +312 -0
  37. package/dist/repertoire/bundle-templates.js +4 -5
  38. package/dist/repertoire/tools-bundle.js +1 -1
  39. package/dist/repertoire/tools-evolution.js +4 -4
  40. package/dist/repertoire/tools-notes.js +42 -62
  41. package/dist/repertoire/tools-record.js +16 -11
  42. package/dist/repertoire/tools-session.js +4 -4
  43. package/dist/repertoire/tools.js +1 -1
  44. package/dist/senses/habit-turn-message.js +19 -5
  45. package/dist/senses/inner-dialog-worker.js +58 -9
  46. package/dist/senses/inner-dialog.js +30 -11
  47. package/dist/senses/pipeline.js +135 -1
  48. package/dist/util/frontmatter.js +17 -1
  49. package/package.json +3 -3
  50. package/skills/configure-dev-tools.md +1 -1
  51. package/skills/travel-planning.md +1 -1
  52. package/dist/mind/journal-index.js +0 -162
@@ -0,0 +1,312 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.resolveDeskRecordPaths = resolveDeskRecordPaths;
37
+ exports.migrateLegacyRecordStores = migrateLegacyRecordStores;
38
+ exports.resolveRecordDiaryRoot = resolveRecordDiaryRoot;
39
+ exports.resolveRecordNotesRoot = resolveRecordNotesRoot;
40
+ exports.resetRecordStoreMigrationTrackingForTests = resetRecordStoreMigrationTrackingForTests;
41
+ const fs = __importStar(require("fs"));
42
+ const path = __importStar(require("path"));
43
+ const identity_1 = require("../heart/identity");
44
+ const runtime_1 = require("../nerves/runtime");
45
+ const migratedAgentRoots = new Set();
46
+ const DERIVED_JOURNAL_INDEX_FILES = new Set([".index.json"]);
47
+ function nowIso() {
48
+ return new Date().toISOString();
49
+ }
50
+ function resolveDeskRecordPaths(agentRoot = (0, identity_1.getAgentRoot)()) {
51
+ const recordRoot = path.join(agentRoot, "desk", "_record");
52
+ const diaryRoot = path.join(recordRoot, "diary");
53
+ return {
54
+ recordRoot,
55
+ diaryRoot,
56
+ diaryDailyDir: path.join(diaryRoot, "daily"),
57
+ factsPath: path.join(diaryRoot, "facts.jsonl"),
58
+ entitiesPath: path.join(diaryRoot, "entities.json"),
59
+ notesRoot: path.join(recordRoot, "notes"),
60
+ migrationReportPath: path.join(recordRoot, "migration-report.jsonl"),
61
+ };
62
+ }
63
+ function appendMigrationReport(paths, entry) {
64
+ fs.mkdirSync(paths.recordRoot, { recursive: true });
65
+ fs.appendFileSync(paths.migrationReportPath, `${JSON.stringify({ schemaVersion: 1, recordedAt: nowIso(), ...entry })}\n`, "utf-8");
66
+ }
67
+ function ensureRecordScaffold(paths) {
68
+ fs.mkdirSync(paths.diaryDailyDir, { recursive: true });
69
+ fs.mkdirSync(paths.notesRoot, { recursive: true });
70
+ if (!fs.existsSync(paths.factsPath))
71
+ fs.writeFileSync(paths.factsPath, "", "utf-8");
72
+ if (!fs.existsSync(paths.entitiesPath))
73
+ fs.writeFileSync(paths.entitiesPath, "{}\n", "utf-8");
74
+ }
75
+ function uniquePathForCollision(destination) {
76
+ const dir = path.dirname(destination);
77
+ const ext = path.extname(destination);
78
+ const base = path.basename(destination, ext);
79
+ for (let index = 1; index < 10_000; index += 1) {
80
+ const candidate = path.join(dir, `${base}.migrated-${index}${ext}`);
81
+ if (!fs.existsSync(candidate))
82
+ return candidate;
83
+ }
84
+ /* v8 ignore next -- defensive exhaustion guard; normal collision allocation is covered @preserve */
85
+ throw new Error(`could not allocate migration collision path for ${destination}`);
86
+ }
87
+ function mergeJsonlFile(source, destination) {
88
+ const sourceText = fs.readFileSync(source, "utf-8");
89
+ if (!fs.existsSync(destination)) {
90
+ fs.writeFileSync(destination, sourceText, "utf-8");
91
+ return "copied";
92
+ }
93
+ const destinationText = fs.readFileSync(destination, "utf-8");
94
+ const existing = new Set(destinationText.split(/\r?\n/).map((line) => line.trim()).filter(Boolean));
95
+ const additions = sourceText.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !existing.has(line));
96
+ if (additions.length === 0)
97
+ return "kept-destination";
98
+ const prefix = destinationText.length > 0 && !destinationText.endsWith("\n") ? "\n" : "";
99
+ fs.appendFileSync(destination, `${prefix}${additions.join("\n")}\n`, "utf-8");
100
+ return "merged";
101
+ }
102
+ function readJsonObject(filePath) {
103
+ try {
104
+ const parsed = JSON.parse(fs.readFileSync(filePath, "utf-8"));
105
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
106
+ }
107
+ catch {
108
+ return null;
109
+ }
110
+ }
111
+ function mergeEntitiesFile(source, destination) {
112
+ if (!fs.existsSync(destination)) {
113
+ fs.copyFileSync(source, destination);
114
+ return "copied";
115
+ }
116
+ const sourceObject = readJsonObject(source);
117
+ const destinationObject = readJsonObject(destination);
118
+ if (!sourceObject || !destinationObject)
119
+ return copyLosslessFile(source, destination) === destination ? "merged" : "copied";
120
+ const conflicts = {};
121
+ const merged = { ...destinationObject };
122
+ for (const [key, value] of Object.entries(sourceObject)) {
123
+ if (!(key in merged)) {
124
+ merged[key] = value;
125
+ continue;
126
+ }
127
+ if (JSON.stringify(merged[key]) !== JSON.stringify(value)) {
128
+ conflicts[key] = value;
129
+ }
130
+ }
131
+ fs.writeFileSync(destination, `${JSON.stringify(merged, null, 2)}\n`, "utf-8");
132
+ if (Object.keys(conflicts).length > 0) {
133
+ const conflictPath = uniquePathForCollision(path.join(path.dirname(destination), "entities.migration-conflicts.json"));
134
+ fs.writeFileSync(conflictPath, `${JSON.stringify(conflicts, null, 2)}\n`, "utf-8");
135
+ }
136
+ return Object.keys(sourceObject).length > 0 ? "merged" : "kept-destination";
137
+ }
138
+ function copyLosslessFile(source, destination) {
139
+ if (!fs.existsSync(destination)) {
140
+ fs.copyFileSync(source, destination);
141
+ return destination;
142
+ }
143
+ const sourceContent = fs.readFileSync(source);
144
+ const destinationContent = fs.readFileSync(destination);
145
+ if (sourceContent.equals(destinationContent))
146
+ return destination;
147
+ if (sourceContent.length > 0 && destinationContent.length === 0) {
148
+ fs.copyFileSync(source, destination);
149
+ return destination;
150
+ }
151
+ const collisionPath = uniquePathForCollision(destination);
152
+ fs.copyFileSync(source, collisionPath);
153
+ return collisionPath;
154
+ }
155
+ function mergeRecordFile(source, destination) {
156
+ fs.mkdirSync(path.dirname(destination), { recursive: true });
157
+ const basename = path.basename(destination);
158
+ if (basename === "facts.jsonl" || destination.endsWith(".jsonl")) {
159
+ mergeJsonlFile(source, destination);
160
+ return;
161
+ }
162
+ if (basename === "entities.json") {
163
+ mergeEntitiesFile(source, destination);
164
+ return;
165
+ }
166
+ copyLosslessFile(source, destination);
167
+ }
168
+ function mergeDirectory(source, destination) {
169
+ fs.mkdirSync(destination, { recursive: true });
170
+ for (const entry of fs.readdirSync(source, { withFileTypes: true })) {
171
+ const sourcePath = path.join(source, entry.name);
172
+ const destinationPath = path.join(destination, entry.name);
173
+ if (entry.isDirectory()) {
174
+ mergeDirectory(sourcePath, destinationPath);
175
+ continue;
176
+ }
177
+ mergeRecordFile(sourcePath, destinationPath);
178
+ }
179
+ }
180
+ function removeDirectoryTree(root) {
181
+ for (const entry of fs.readdirSync(root, { withFileTypes: true })) {
182
+ const entryPath = path.join(root, entry.name);
183
+ if (entry.isDirectory()) {
184
+ removeDirectoryTree(entryPath);
185
+ continue;
186
+ }
187
+ fs.rmSync(entryPath, { force: true });
188
+ }
189
+ fs.rmdirSync(root);
190
+ }
191
+ function moveOrMergeDirectory(paths, source, destination, reason) {
192
+ if (!fs.existsSync(source))
193
+ return;
194
+ fs.mkdirSync(path.dirname(destination), { recursive: true });
195
+ mergeDirectory(source, destination);
196
+ removeDirectoryTree(source);
197
+ appendMigrationReport(paths, { action: "merged", source, destination, reason });
198
+ }
199
+ function quarantineJournalFile(paths, sourcePath, relativePath, reason) {
200
+ const destinationPath = path.join(paths.recordRoot, "migration-quarantine", "journal", relativePath);
201
+ fs.mkdirSync(path.dirname(destinationPath), { recursive: true });
202
+ copyLosslessFile(sourcePath, destinationPath);
203
+ appendMigrationReport(paths, { action: "quarantined", source: sourcePath, destination: destinationPath, reason });
204
+ }
205
+ function slugFromJournalFile(filename) {
206
+ const base = filename.replace(/\.[^.]+$/, "");
207
+ const slug = base
208
+ .toLowerCase()
209
+ .replace(/[^a-z0-9]+/g, "-")
210
+ .replace(/^-+|-+$/g, "")
211
+ .slice(0, 80)
212
+ .replace(/-+$/g, "");
213
+ return slug || "entry";
214
+ }
215
+ function migrateJournalEntry(paths, sourcePath, relativePath) {
216
+ const entryName = path.basename(sourcePath);
217
+ if (DERIVED_JOURNAL_INDEX_FILES.has(entryName)) {
218
+ appendMigrationReport(paths, {
219
+ action: "dropped",
220
+ source: sourcePath,
221
+ reason: "derived journal index is obsolete after Desk record migration",
222
+ });
223
+ return;
224
+ }
225
+ const extension = path.extname(entryName).toLowerCase();
226
+ if (extension !== ".md" && extension !== ".txt") {
227
+ quarantineJournalFile(paths, sourcePath, relativePath, "non-text journal scratch quarantined after Desk record migration");
228
+ return;
229
+ }
230
+ const relativeSlug = slugFromJournalFile(relativePath.split(path.sep).join("-"));
231
+ const destinationPath = copyLosslessFile(sourcePath, path.join(paths.notesRoot, `journal-${relativeSlug}.md`));
232
+ appendMigrationReport(paths, {
233
+ action: "moved",
234
+ source: sourcePath,
235
+ destination: destinationPath,
236
+ reason: "journal text migrated into Desk record notes",
237
+ });
238
+ }
239
+ function migrateJournalTree(paths, root, current) {
240
+ for (const entry of fs.readdirSync(current, { withFileTypes: true })) {
241
+ const sourcePath = path.join(current, entry.name);
242
+ if (entry.isDirectory()) {
243
+ migrateJournalTree(paths, root, sourcePath);
244
+ continue;
245
+ }
246
+ migrateJournalEntry(paths, sourcePath, path.relative(root, sourcePath));
247
+ }
248
+ }
249
+ function migrateJournalIntoNotes(paths, agentRoot) {
250
+ const journalRoot = path.join(agentRoot, "journal");
251
+ if (!fs.existsSync(journalRoot))
252
+ return;
253
+ fs.mkdirSync(paths.notesRoot, { recursive: true });
254
+ migrateJournalTree(paths, journalRoot, journalRoot);
255
+ removeDirectoryTree(journalRoot);
256
+ appendMigrationReport(paths, {
257
+ action: "removed",
258
+ source: journalRoot,
259
+ reason: "top-level journal is no longer an active substrate",
260
+ });
261
+ }
262
+ function migrateLegacyRecordStores(agentRoot = (0, identity_1.getAgentRoot)()) {
263
+ const paths = resolveDeskRecordPaths(agentRoot);
264
+ const legacyRoots = [
265
+ path.join(agentRoot, "psyche", "mem" + "ory"),
266
+ path.join(agentRoot, "diary"),
267
+ path.join(agentRoot, "notes"),
268
+ path.join(agentRoot, "journal"),
269
+ ];
270
+ if (migratedAgentRoots.has(agentRoot) && !legacyRoots.some((root) => fs.existsSync(root))) {
271
+ ensureRecordScaffold(paths);
272
+ return paths;
273
+ }
274
+ migratedAgentRoots.add(agentRoot);
275
+ (0, runtime_1.emitNervesEvent)({
276
+ component: "mind",
277
+ event: "mind.record_store_migration_start",
278
+ message: "record store migration started",
279
+ meta: { agentRoot, recordRoot: paths.recordRoot },
280
+ });
281
+ ensureRecordScaffold(paths);
282
+ moveOrMergeDirectory(paths, path.join(agentRoot, "psyche", "mem" + "ory"), paths.diaryRoot, "legacy pre-diary fact store moved into Desk record diary");
283
+ moveOrMergeDirectory(paths, path.join(agentRoot, "diary"), paths.diaryRoot, "top-level diary moved into Desk record diary");
284
+ moveOrMergeDirectory(paths, path.join(agentRoot, "notes"), paths.notesRoot, "top-level notes moved into Desk record notes");
285
+ const staleNotesIndex = path.join(paths.notesRoot, ".index.json");
286
+ if (fs.existsSync(staleNotesIndex)) {
287
+ fs.rmSync(staleNotesIndex, { force: true });
288
+ appendMigrationReport(paths, {
289
+ action: "removed",
290
+ source: staleNotesIndex,
291
+ reason: "canonical notes index stores file paths and must be rebuilt after migration",
292
+ });
293
+ }
294
+ migrateJournalIntoNotes(paths, agentRoot);
295
+ ensureRecordScaffold(paths);
296
+ (0, runtime_1.emitNervesEvent)({
297
+ component: "mind",
298
+ event: "mind.record_store_migration_end",
299
+ message: "record store migration completed",
300
+ meta: { agentRoot, recordRoot: paths.recordRoot },
301
+ });
302
+ return paths;
303
+ }
304
+ function resolveRecordDiaryRoot(agentRoot = (0, identity_1.getAgentRoot)()) {
305
+ return migrateLegacyRecordStores(agentRoot).diaryRoot;
306
+ }
307
+ function resolveRecordNotesRoot(agentRoot = (0, identity_1.getAgentRoot)()) {
308
+ return migrateLegacyRecordStores(agentRoot).notesRoot;
309
+ }
310
+ function resetRecordStoreMigrationTrackingForTests() {
311
+ migratedAgentRoots.clear();
312
+ }
@@ -14,7 +14,7 @@
14
14
  * - Build artifacts (rare in bundles, but possible).
15
15
  *
16
16
  * It DOES NOT handle PII. The bundle is inherently full of PII — `friends/`,
17
- * `diary/`, `journal/`, `psyche/`, `arc/`, `facts/`, `family/`, `travel/`
17
+ * `desk/_record/`, `psyche/`, `arc/`, `facts/`, `family/`, `travel/`
18
18
  * etc. That's the point of the bundle; blocking those via .gitignore would
19
19
  * defeat the purpose.
20
20
  *
@@ -54,19 +54,18 @@ node_modules/
54
54
  dist/
55
55
  `;
56
56
  /**
57
- * PII-sensitive top-level directories. Enumerated here so `bundle_first_push_review`
57
+ * PII-sensitive bundle directories. Enumerated here so `bundle_first_push_review`
58
58
  * can categorize and count. Adding a new PII bucket to the bundle means adding
59
59
  * it here so the first-push warning includes it.
60
60
  */
61
61
  exports.PII_BUNDLE_DIRECTORIES = [
62
62
  "friends",
63
- "diary",
64
- "journal",
63
+ "desk/_record/diary",
64
+ "desk/_record/notes",
65
65
  "psyche",
66
66
  "arc",
67
67
  "facts",
68
68
  "family",
69
69
  "travel",
70
- "notes",
71
70
  "sessions",
72
71
  ];
@@ -944,7 +944,7 @@ exports.bundleToolDefinitions = [
944
944
  type: "function",
945
945
  function: {
946
946
  name: "bundle_first_push_review",
947
- description: "Review my bundle for PII exposure before the first push to a new remote. Enumerates PII-bearing directories (friends, diary, journal, etc.) with per-directory counts, probes the remote URL for GitHub public/private visibility, and returns a first-person warning text I must show the human plus a confirmationToken I must pass to bundle_push on first push. Required before the first push to any new remote.",
947
+ description: "Review my bundle for PII exposure before the first push to a new remote. Enumerates PII-bearing directories (friends, Desk record, Arc, etc.) with per-directory counts, probes the remote URL for GitHub public/private visibility, and returns a first-person warning text I must show the human plus a confirmationToken I must pass to bundle_push on first push. Required before the first push to any new remote.",
948
948
  parameters: { type: "object", properties: {} },
949
949
  },
950
950
  },
@@ -8,7 +8,7 @@ const runtime_1 = require("../nerves/runtime");
8
8
  const EVOLUTION_ACTIONS = new Set([
9
9
  "create_case",
10
10
  "add_evidence",
11
- "write_journal",
11
+ "write_record",
12
12
  "write_desk",
13
13
  "write_diary",
14
14
  "spawn_coding",
@@ -46,7 +46,7 @@ const EVIDENCE_KINDS = new Set([
46
46
  "release",
47
47
  "installed_runtime",
48
48
  "diary_entry",
49
- "journal_file",
49
+ "desk_record_note",
50
50
  "skill_file",
51
51
  "sense_artifact",
52
52
  "hosted_audit",
@@ -54,7 +54,7 @@ const EVIDENCE_KINDS = new Set([
54
54
  "external_doc",
55
55
  ]);
56
56
  const REDACTIONS = new Set(["none", "summary", "private_ref", "secret_ref"]);
57
- const DECISIONS = new Set(["ignore", "defer", "journal", "ask", "delegate", "act", "abandon"]);
57
+ const DECISIONS = new Set(["ignore", "defer", "record", "ask", "delegate", "act", "abandon"]);
58
58
  const VERIFICATION_STATUSES = new Set(["not-verified", "partial", "passed", "failed"]);
59
59
  const RATIFICATION_DESTINATIONS = new Set([
60
60
  "code",
@@ -63,7 +63,7 @@ const RATIFICATION_DESTINATIONS = new Set([
63
63
  "desk_lesson",
64
64
  "desk_task",
65
65
  "diary",
66
- "journal",
66
+ "desk_record",
67
67
  "habit",
68
68
  "policy",
69
69
  "agent_config",
@@ -1,45 +1,9 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
2
  Object.defineProperty(exports, "__esModule", { value: true });
36
3
  exports.notesToolDefinitions = void 0;
37
- const fs = __importStar(require("fs"));
38
- const path = __importStar(require("path"));
39
4
  const child_process_1 = require("child_process");
40
5
  const skills_1 = require("./skills");
41
6
  const config_1 = require("../heart/config");
42
- const identity_1 = require("../heart/identity");
43
7
  const runtime_1 = require("../nerves/runtime");
44
8
  const diary_1 = require("../mind/diary");
45
9
  const provenance_trust_1 = require("../mind/provenance-trust");
@@ -170,8 +134,8 @@ exports.notesToolDefinitions = [
170
134
  tool: {
171
135
  type: "function",
172
136
  function: {
173
- name: "search_notes",
174
- description: "Search my diary and journal for facts, thoughts, and working notes matching a query. Uses semantic similarity -- phrasing matters. Try different angles if the first query doesn't find what you're looking for. Search written notes before asking the human something the notes may already answer.",
137
+ name: "search_facts",
138
+ description: "Search my Desk record diary facts matching a query. Uses semantic similarity -- phrasing matters. Try different angles if the first query doesn't find what you're looking for. Search written facts before asking the human something the record may already answer.",
175
139
  parameters: {
176
140
  type: "object",
177
141
  properties: { query: { type: "string" } },
@@ -185,7 +149,6 @@ exports.notesToolDefinitions = [
185
149
  if (!query)
186
150
  return "query is required";
187
151
  const resultLines = [];
188
- // Search diary entries
189
152
  const hits = await (0, diary_1.searchDiaryEntries)(query, (0, diary_1.readDiaryEntries)());
190
153
  for (const fact of hits) {
191
154
  let meta = `source=${fact.source}, createdAt=${fact.createdAt}`;
@@ -200,35 +163,52 @@ exports.notesToolDefinitions = [
200
163
  const tag = (0, provenance_trust_1.classifyProvenanceTrust)(fact.provenance) === "external" ? "diary/external" : "diary";
201
164
  resultLines.push(`[${tag}] ${fact.text} (${meta})`);
202
165
  }
203
- // Search journal index
204
- const agentRoot = (0, identity_1.getAgentRoot)();
205
- const journalIndexPath = path.join(agentRoot, "journal", ".index.json");
206
- try {
207
- const raw = fs.readFileSync(journalIndexPath, "utf8");
208
- const journalEntries = JSON.parse(raw);
209
- if (Array.isArray(journalEntries) && journalEntries.length > 0) {
210
- // Substring match on preview and filename
211
- const lowerQuery = query.toLowerCase();
212
- for (const entry of journalEntries) {
213
- /* v8 ignore next 4 -- both sides tested (filename-only match in search_notes-journal.test.ts); v8 misreports || short-circuit @preserve */
214
- if (entry.preview.toLowerCase().includes(lowerQuery) ||
215
- entry.filename.toLowerCase().includes(lowerQuery)) {
216
- resultLines.push(`[journal] ${entry.filename}: ${entry.preview}`);
217
- }
218
- }
219
- }
220
- }
221
- catch {
222
- // No journal index or malformed — skip journal search
223
- }
224
166
  return resultLines.join("\n");
225
167
  }
226
168
  catch (e) {
227
- return `error: ${e instanceof Error ? e.message : String(e)}`;
169
+ return `error: ${e instanceof Error ? e.message : /* v8 ignore next -- defensive: non-Error catch branch @preserve */ String(e)}`;
228
170
  }
229
171
  },
230
172
  summaryKeys: ["query"],
231
173
  },
174
+ {
175
+ tool: {
176
+ type: "function",
177
+ function: {
178
+ name: "consult_diary",
179
+ description: "Inspect my Desk record diary facts. With a query, searches semantically. Without a query, returns the most recent facts. Use this for direct record inspection before asking someone to restate something already written down.",
180
+ parameters: {
181
+ type: "object",
182
+ properties: {
183
+ query: { type: "string" },
184
+ limit: { type: "string" },
185
+ },
186
+ },
187
+ },
188
+ },
189
+ handler: async (a) => {
190
+ try {
191
+ const limitRaw = a.limit ? Number.parseInt(String(a.limit), 10) : 10;
192
+ const limit = Number.isFinite(limitRaw) ? Math.min(50, Math.max(1, limitRaw)) : 10;
193
+ const query = typeof a.query === "string" ? a.query.trim() : "";
194
+ const facts = (0, diary_1.readDiaryEntries)();
195
+ const matches = query ? await (0, diary_1.searchDiaryEntries)(query, facts) : [...facts].sort((left, right) => right.createdAt.localeCompare(left.createdAt));
196
+ const items = matches.slice(0, limit).map((fact) => ({
197
+ id: fact.id,
198
+ text: fact.text,
199
+ source: fact.source,
200
+ createdAt: fact.createdAt,
201
+ ...(fact.about ? { about: fact.about } : {}),
202
+ ...(fact.provenance ? { provenance: fact.provenance } : {}),
203
+ }));
204
+ return JSON.stringify({ items });
205
+ }
206
+ catch (e) {
207
+ return `error: ${e instanceof Error ? e.message : /* v8 ignore next -- defensive: non-Error catch branch @preserve */ String(e)}`;
208
+ }
209
+ },
210
+ summaryKeys: ["query", "limit"],
211
+ },
232
212
  {
233
213
  tool: {
234
214
  type: "function",
@@ -275,7 +255,7 @@ exports.notesToolDefinitions = [
275
255
  return `saved diary entry (added=${result.added}, skipped=${result.skipped})`;
276
256
  },
277
257
  summaryKeys: ["entry", "about"],
278
- riskProfile: { mutates: "durable_state_write", risk: "high", reason: "writes diary memory" },
258
+ riskProfile: { mutates: "durable_state_write", risk: "high", reason: "writes Desk record diary fact" },
279
259
  },
280
260
  {
281
261
  tool: {
@@ -37,9 +37,10 @@ exports.recordToolDefinitions = void 0;
37
37
  const fs = __importStar(require("fs"));
38
38
  const path = __importStar(require("path"));
39
39
  const session_events_1 = require("../heart/session-events");
40
- const identity_1 = require("../heart/identity");
41
40
  const embedding_provider_1 = require("../mind/embedding-provider");
42
41
  const note_search_1 = require("../mind/note-search");
42
+ const record_paths_1 = require("../mind/record-paths");
43
+ const types_1 = require("../mind/friends/types");
43
44
  const runtime_1 = require("../nerves/runtime");
44
45
  const NOTES_INDEX_VERSION = 1;
45
46
  const NOTE_SLUG_MAX_CHARS = 40;
@@ -54,6 +55,12 @@ function hasSelfTrust(ctx) {
54
55
  const friend = ctx?.context?.friend;
55
56
  return !friend || friend.id === "self";
56
57
  }
58
+ function hasRecordReadTrust(ctx) {
59
+ if (hasSelfTrust(ctx))
60
+ return true;
61
+ const friend = ctx?.context?.friend;
62
+ return Boolean(friend) && (0, types_1.isTrustedLevel)(friend?.trustLevel);
63
+ }
57
64
  function normalizeTags(value) {
58
65
  if (value === undefined || value === null)
59
66
  return undefined;
@@ -224,8 +231,6 @@ function indexFreshForRecords(index, records) {
224
231
  const recordsByFilename = new Map(records.map((record) => [record.filename, record]));
225
232
  const seenFilenames = new Set();
226
233
  for (const entry of index.entries) {
227
- if (seenFilenames.has(entry.filename))
228
- return false;
229
234
  const record = recordsByFilename.get(entry.filename);
230
235
  if (!record || !entryMatchesRecord(entry, record))
231
236
  return false;
@@ -331,7 +336,7 @@ exports.recordToolDefinitions = [
331
336
  type: "function",
332
337
  function: {
333
338
  name: "note",
334
- description: "Write a durable self note as canonical markdown in my notes folder. Only available to my self/inner context, not external callers.",
339
+ description: "Write a durable self note as canonical markdown in my Desk record notes. Only available to my self/inner context, not external callers.",
335
340
  parameters: {
336
341
  type: "object",
337
342
  properties: {
@@ -359,9 +364,9 @@ exports.recordToolDefinitions = [
359
364
  const createdAt = new Date().toISOString();
360
365
  const date = createdAt.slice(0, 10);
361
366
  const tags = normalizeTags(rawArgs.tags);
362
- const notesDir = path.join((0, identity_1.getAgentRoot)(), "notes");
363
- const indexPath = path.join(notesDir, ".index.json");
364
367
  try {
368
+ const notesDir = (0, record_paths_1.resolveRecordNotesRoot)();
369
+ const indexPath = path.join(notesDir, ".index.json");
365
370
  fs.mkdirSync(notesDir, { recursive: true });
366
371
  const savedPath = ensureUniquePath(notesDir, date, slugForContent(content));
367
372
  fs.writeFileSync(savedPath, renderNote(createdAt, cappedContent, tags), "utf8");
@@ -386,14 +391,14 @@ exports.recordToolDefinitions = [
386
391
  }
387
392
  },
388
393
  summaryKeys: ["content", "tags"],
389
- riskProfile: { mutates: "durable_state_write", risk: "high", reason: "writes canonical note memory" },
394
+ riskProfile: { mutates: "durable_state_write", risk: "high", reason: "writes canonical Desk record note" },
390
395
  },
391
396
  {
392
397
  tool: {
393
398
  type: "function",
394
399
  function: {
395
400
  name: "consult_notes",
396
- description: "Search my canonical markdown notes semantically using the notes-native index. Only available to my self/inner context, not external callers.",
401
+ description: "Search my canonical markdown Desk record notes semantically using the notes-native index. Read-only orientation lookup for trusted callers.",
397
402
  parameters: {
398
403
  type: "object",
399
404
  properties: {
@@ -407,13 +412,13 @@ exports.recordToolDefinitions = [
407
412
  },
408
413
  },
409
414
  handler: async (args, ctx) => {
410
- if (!hasSelfTrust(ctx))
411
- return "error: consult_notes requires self trust and cannot be used from an external caller context.";
415
+ if (!hasRecordReadTrust(ctx))
416
+ return "error: consult_notes requires trusted record-read access.";
412
417
  const rawArgs = args;
413
418
  const query = typeof rawArgs.query === "string" ? rawArgs.query.trim() : "";
414
419
  if (!query)
415
420
  return JSON.stringify({ items: [] });
416
- const notesDir = path.join((0, identity_1.getAgentRoot)(), "notes");
421
+ const notesDir = (0, record_paths_1.resolveRecordNotesRoot)();
417
422
  const indexPath = path.join(notesDir, ".index.json");
418
423
  const records = listCanonicalNotes(notesDir);
419
424
  if (records.length === 0)
@@ -361,7 +361,7 @@ exports.sessionToolDefinitions = [
361
361
  type: "function",
362
362
  function: {
363
363
  name: "query_session",
364
- description: "inspect another session. use transcript for recent context or status for self/inner progress. deprecated search invocations should use search_notes or consult_notes instead.",
364
+ description: "inspect another session. use transcript for recent context or status for self/inner progress. deprecated search invocations should use search_facts, consult_diary, or consult_notes instead.",
365
365
  parameters: {
366
366
  type: "object",
367
367
  properties: {
@@ -372,9 +372,9 @@ exports.sessionToolDefinitions = [
372
372
  mode: {
373
373
  type: "string",
374
374
  enum: ["transcript", "status", "search"],
375
- description: "transcript (default), lightweight status for self/inner checks, or deprecated search; use search_notes or consult_notes instead",
375
+ description: "transcript (default), lightweight status for self/inner checks, or deprecated search; use search_facts, consult_diary, or consult_notes instead",
376
376
  },
377
- query: { type: "string", description: "deprecated when mode=search; use search_notes or consult_notes instead" },
377
+ query: { type: "string", description: "deprecated when mode=search; use search_facts, consult_diary, or consult_notes instead" },
378
378
  },
379
379
  required: ["friendId", "channel"],
380
380
  },
@@ -405,7 +405,7 @@ exports.sessionToolDefinitions = [
405
405
  if (mode === "search") {
406
406
  return JSON.stringify({
407
407
  kind: "deprecated",
408
- message: "query_session mode=search is no longer available; use search_notes or consult_notes instead.",
408
+ message: "query_session mode=search is no longer available; use search_facts, consult_diary, or consult_notes instead.",
409
409
  removalCycle: "alpha.616",
410
410
  });
411
411
  }
@@ -203,7 +203,7 @@ function riskProfileForTool(def, name, args) {
203
203
  return def.riskProfile ?? { mutates: "none", risk: "low" };
204
204
  }
205
205
  function orientationHoldMessage(name, profile, reason) {
206
- return `orientation hold: ${reason} Available: orientation_get plus read-only inspection tools like trip_status, query_session, read_config, read_file, grep, and search_notes. Resolve the referent/correction, then retry ${name} if the action is still correct. Blocked ${mutationKindsFor(profile).join(", ")}. ${profile.reason}.`;
206
+ return `orientation hold: ${reason} Available: orientation_get plus read-only inspection tools like trip_status, query_session, read_config, read_file, grep, search_facts, consult_diary, and consult_notes. Resolve the referent/correction, then retry ${name} if the action is still correct. Blocked ${mutationKindsFor(profile).join(", ")}. ${profile.reason}.`;
207
207
  }
208
208
  function mutationKindsFor(profile) {
209
209
  const mutates = profile.mutates;