@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.
- package/README.md +13 -13
- package/changelog.json +9 -0
- package/dist/arc/evolution.js +1 -1
- package/dist/arc/flight-recorder.js +369 -0
- package/dist/arc/obligations.js +24 -2
- package/dist/heart/active-work.js +1 -1
- package/dist/heart/config-registry.js +5 -5
- package/dist/heart/daemon/agent-config-check.js +1 -1
- package/dist/heart/daemon/agent-service.js +18 -17
- package/dist/heart/daemon/cli-exec.js +27 -12
- package/dist/heart/daemon/cli-help.js +14 -0
- package/dist/heart/daemon/cli-parse.js +26 -0
- package/dist/heart/daemon/daemon-entry.js +1 -1
- package/dist/heart/daemon/daemon.js +3 -3
- package/dist/heart/daemon/hooks/bundle-meta.js +29 -9
- package/dist/heart/daemon/inner-status.js +4 -15
- package/dist/heart/habits/habit-parser.js +64 -1
- package/dist/heart/hatch/hatch-flow.js +17 -9
- package/dist/heart/hatch/specialist-tools.js +15 -11
- package/dist/heart/kept-notes.js +5 -73
- package/dist/heart/mailbox/readers/runtime-readers.js +21 -49
- package/dist/heart/mcp/mcp-server.js +8 -8
- package/dist/heart/session-events.js +1 -31
- package/dist/heart/start-of-turn-packet.js +8 -2
- package/dist/heart/tool-description.js +15 -3
- package/dist/heart/turn-context.js +27 -7
- package/dist/heart/work-card.js +386 -0
- package/dist/mailbox-ui/assets/{index-9-AxCxuB.js → index-Cbasiy6y.js} +1 -1
- package/dist/mailbox-ui/index.html +1 -1
- package/dist/mind/bundle-manifest.js +9 -3
- package/dist/mind/context.js +1 -2
- package/dist/mind/desk-section.js +53 -1
- package/dist/mind/diary.js +2 -3
- package/dist/mind/note-search.js +36 -106
- package/dist/mind/prompt.js +37 -102
- package/dist/mind/record-paths.js +312 -0
- package/dist/repertoire/bundle-templates.js +4 -5
- package/dist/repertoire/tools-bundle.js +1 -1
- package/dist/repertoire/tools-evolution.js +4 -4
- package/dist/repertoire/tools-notes.js +42 -62
- package/dist/repertoire/tools-record.js +16 -11
- package/dist/repertoire/tools-session.js +4 -4
- package/dist/repertoire/tools.js +1 -1
- package/dist/senses/habit-turn-message.js +19 -5
- package/dist/senses/inner-dialog-worker.js +58 -9
- package/dist/senses/inner-dialog.js +30 -11
- package/dist/senses/pipeline.js +135 -1
- package/dist/util/frontmatter.js +17 -1
- package/package.json +3 -3
- package/skills/configure-dev-tools.md +1 -1
- package/skills/travel-planning.md +1 -1
- 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
|
-
* `
|
|
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
|
|
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
|
-
"
|
|
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,
|
|
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
|
-
"
|
|
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
|
-
"
|
|
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", "
|
|
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
|
-
"
|
|
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: "
|
|
174
|
-
description: "Search my
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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 (!
|
|
411
|
-
return "error: consult_notes requires
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
}
|
package/dist/repertoire/tools.js
CHANGED
|
@@ -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
|
|
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;
|