@ouro.bot/cli 0.1.0-alpha.655 → 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 (55) hide show
  1. package/README.md +13 -13
  2. package/changelog.json +21 -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 +14 -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 +134 -15
  11. package/dist/heart/daemon/cli-help.js +21 -2
  12. package/dist/heart/daemon/cli-parse.js +31 -3
  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/daemon/sense-manager.js +16 -1
  18. package/dist/heart/habits/habit-parser.js +64 -1
  19. package/dist/heart/hatch/hatch-flow.js +17 -9
  20. package/dist/heart/hatch/specialist-tools.js +15 -11
  21. package/dist/heart/identity.js +4 -1
  22. package/dist/heart/kept-notes.js +5 -73
  23. package/dist/heart/mailbox/readers/runtime-readers.js +21 -49
  24. package/dist/heart/mcp/mcp-server.js +8 -8
  25. package/dist/heart/sense-truth.js +2 -0
  26. package/dist/heart/session-events.js +1 -31
  27. package/dist/heart/start-of-turn-packet.js +8 -2
  28. package/dist/heart/tool-description.js +15 -3
  29. package/dist/heart/turn-context.js +34 -7
  30. package/dist/heart/work-card.js +386 -0
  31. package/dist/mailbox-ui/assets/{index-9-AxCxuB.js → index-Cbasiy6y.js} +1 -1
  32. package/dist/mailbox-ui/index.html +1 -1
  33. package/dist/mind/bundle-manifest.js +9 -3
  34. package/dist/mind/context.js +1 -2
  35. package/dist/mind/desk-section.js +53 -1
  36. package/dist/mind/diary.js +2 -3
  37. package/dist/mind/note-search.js +36 -106
  38. package/dist/mind/prompt.js +45 -102
  39. package/dist/mind/record-paths.js +312 -0
  40. package/dist/repertoire/bundle-templates.js +4 -5
  41. package/dist/repertoire/tools-bundle.js +1 -1
  42. package/dist/repertoire/tools-evolution.js +4 -4
  43. package/dist/repertoire/tools-notes.js +42 -62
  44. package/dist/repertoire/tools-record.js +16 -11
  45. package/dist/repertoire/tools-session.js +4 -4
  46. package/dist/repertoire/tools.js +1 -1
  47. package/dist/senses/habit-turn-message.js +19 -5
  48. package/dist/senses/inner-dialog-worker.js +58 -9
  49. package/dist/senses/inner-dialog.js +30 -11
  50. package/dist/senses/pipeline.js +135 -1
  51. package/dist/util/frontmatter.js +17 -1
  52. package/package.json +3 -3
  53. package/skills/configure-dev-tools.md +1 -1
  54. package/skills/travel-planning.md +1 -1
  55. package/dist/mind/journal-index.js +0 -162
@@ -24,7 +24,7 @@ function formatCadence(cadenceMs) {
24
24
  return `${minutes}m`;
25
25
  }
26
26
  function buildInnerStatusOutput(input) {
27
- const { agentName, runtimeState, journalFiles, heartbeat, attentionCount, now } = input;
27
+ const { agentName, runtimeState, recordSummary, heartbeat, attentionCount, now } = input;
28
28
  const lines = [];
29
29
  lines.push(`inner dialog status: ${agentName}`);
30
30
  // Last turn
@@ -58,19 +58,7 @@ function buildInnerStatusOutput(input) {
58
58
  else {
59
59
  lines.push(" heartbeat: unknown");
60
60
  }
61
- // Journal
62
- if (journalFiles.length === 0) {
63
- lines.push(" journal: (empty)");
64
- }
65
- else {
66
- lines.push(" journal:");
67
- const sorted = [...journalFiles].sort((a, b) => b.mtimeMs - a.mtimeMs);
68
- for (const file of sorted) {
69
- const elapsed = now - file.mtimeMs;
70
- const relativeTime = formatRelativeTime(elapsed);
71
- lines.push(` - ${file.name} (${relativeTime})`);
72
- }
73
- }
61
+ lines.push(` Desk record: ${recordSummary.diaryFactCount} diary facts, ${recordSummary.noteCount} notes`);
74
62
  // Attention
75
63
  const thoughtWord = attentionCount === 1 ? "thought" : "thoughts";
76
64
  lines.push(` attention: ${attentionCount} held ${thoughtWord}`);
@@ -81,7 +69,8 @@ function buildInnerStatusOutput(input) {
81
69
  meta: {
82
70
  agentName,
83
71
  status: runtimeState?.status ?? "unknown",
84
- journalCount: journalFiles.length,
72
+ diaryFactCount: recordSummary.diaryFactCount,
73
+ noteCount: recordSummary.noteCount,
85
74
  attentionCount,
86
75
  },
87
76
  });
@@ -57,6 +57,7 @@ function defaultSenses() {
57
57
  mail: { ...identity_1.DEFAULT_AGENT_SENSES.mail },
58
58
  voice: { ...identity_1.DEFAULT_AGENT_SENSES.voice },
59
59
  a2a: { ...identity_1.DEFAULT_AGENT_SENSES.a2a },
60
+ workbench: { ...identity_1.DEFAULT_AGENT_SENSES.workbench },
60
61
  };
61
62
  }
62
63
  function readAgentSenses(agentJsonPath) {
@@ -82,7 +83,7 @@ function readAgentSenses(agentJsonPath) {
82
83
  if (!rawSenses || typeof rawSenses !== "object" || Array.isArray(rawSenses)) {
83
84
  return defaults;
84
85
  }
85
- for (const sense of ["cli", "teams", "bluebubbles", "mail", "voice", "a2a"]) {
86
+ for (const sense of ["cli", "teams", "bluebubbles", "mail", "voice", "a2a", "workbench"]) {
86
87
  const rawSense = rawSenses[sense];
87
88
  if (!rawSense || typeof rawSense !== "object" || Array.isArray(rawSense)) {
88
89
  continue;
@@ -147,6 +148,7 @@ function senseFactsFromRuntimeConfig(agent, senses, runtimeConfig, machineRuntim
147
148
  mail: { configured: false, detail: "not enabled in agent.json" },
148
149
  voice: { configured: false, detail: "not enabled in agent.json" },
149
150
  a2a: { configured: false, detail: "not enabled in agent.json" },
151
+ workbench: { configured: false, detail: "not enabled in agent.json" },
150
152
  };
151
153
  const payload = runtimeConfig.ok ? runtimeConfig.config : {};
152
154
  const unavailableDetail = runtimeConfigUnavailableDetail(agent, runtimeConfig);
@@ -301,6 +303,12 @@ function senseFactsFromRuntimeConfig(agent, senses, runtimeConfig, machineRuntim
301
303
  detail: publicUrl ? `${publicUrl}${endpointPath}` : `:${port} ${endpointPath}`,
302
304
  };
303
305
  }
306
+ if (senses.workbench.enabled) {
307
+ base.workbench = {
308
+ configured: true,
309
+ detail: "native Workbench local control room; MCP registration is stored in agent.json",
310
+ };
311
+ }
304
312
  return base;
305
313
  }
306
314
  function senseRepairHint(agent, sense) {
@@ -317,6 +325,10 @@ function senseRepairHint(agent, sense) {
317
325
  if (sense === "a2a") {
318
326
  return `Agent-runnable: run 'ouro connect a2a --agent ${agent}', then restart with 'ouro up'.`;
319
327
  }
328
+ /* v8 ignore next -- Workbench is deliberately not daemon-managed, so getSenseInventory never asks the daemon manager for a repair hint @preserve */
329
+ if (sense === "workbench") {
330
+ return `Agent-runnable: run 'ouro connect workbench --agent ${agent}' to enable senses.workbench.enabled and mcpServers.ouro_workbench in agent.json.`;
331
+ }
320
332
  return `Run 'ouro connect bluebubbles --agent ${agent}' to attach BlueBubbles on this machine; then run 'ouro up' again.`;
321
333
  }
322
334
  function currentMachineId() {
@@ -768,6 +780,9 @@ class DaemonSenseManager {
768
780
  configured: context.facts.a2a.configured,
769
781
  ...(runtime.get(agent)?.a2a ?? {}),
770
782
  },
783
+ workbench: {
784
+ configured: context.facts.workbench.configured,
785
+ },
771
786
  };
772
787
  const inventory = (0, sense_truth_1.getSenseInventory)({ senses: context.senses }, runtimeInfo);
773
788
  return inventory.map((entry) => ({
@@ -57,6 +57,53 @@ function parseToolsField(raw) {
57
57
  }
58
58
  return undefined;
59
59
  }
60
+ function objectRecord(raw) {
61
+ return raw && typeof raw === "object" && !Array.isArray(raw) ? raw : null;
62
+ }
63
+ function stringField(record, key) {
64
+ const value = record[key];
65
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
66
+ }
67
+ function booleanField(record, key, fallback) {
68
+ const value = record[key];
69
+ if (typeof value === "boolean")
70
+ return value;
71
+ if (typeof value === "string") {
72
+ if (value === "true")
73
+ return true;
74
+ if (value === "false")
75
+ return false;
76
+ }
77
+ return fallback;
78
+ }
79
+ function parseStringArray(raw) {
80
+ if (typeof raw === "string" && raw.startsWith("[") && raw.endsWith("]")) {
81
+ const inner = raw.slice(1, -1);
82
+ if (!inner.trim())
83
+ return [];
84
+ return inner.split(",").map((item) => item.trim()).filter(Boolean);
85
+ }
86
+ return [];
87
+ }
88
+ function parseOrigin(raw) {
89
+ const record = objectRecord(raw);
90
+ if (!record)
91
+ return null;
92
+ const friendId = stringField(record, "friendId");
93
+ const channel = stringField(record, "channel");
94
+ const key = stringField(record, "key");
95
+ if (!friendId || !channel || !key)
96
+ return null;
97
+ return { friendId, channel, key };
98
+ }
99
+ function parseSurface(raw) {
100
+ const record = objectRecord(raw);
101
+ return {
102
+ family: record ? booleanField(record, "family", true) : true,
103
+ originator: record ? booleanField(record, "originator", true) : true,
104
+ extra: record ? parseStringArray(record.extra) : [],
105
+ };
106
+ }
60
107
  function extractFrontmatterAndBody(content) {
61
108
  const lines = content.split(/\r?\n/);
62
109
  if (lines[0]?.trim() !== "---") {
@@ -88,6 +135,8 @@ function parseHabitFile(content, filePath) {
88
135
  lastRun: null,
89
136
  created: null,
90
137
  tools: undefined,
138
+ origin: null,
139
+ surface: { family: true, originator: true, extra: [] },
91
140
  body: content.trim(),
92
141
  };
93
142
  }
@@ -103,6 +152,8 @@ function parseHabitFile(content, filePath) {
103
152
  const rawCreated = frontmatter.created;
104
153
  const created = typeof rawCreated === "string" && rawCreated.length > 0 ? rawCreated : null;
105
154
  const tools = parseToolsField(frontmatter.tools);
155
+ const origin = parseOrigin(frontmatter.origin);
156
+ const surface = parseSurface(frontmatter.surface);
106
157
  return {
107
158
  name: stem,
108
159
  title,
@@ -111,6 +162,8 @@ function parseHabitFile(content, filePath) {
111
162
  lastRun,
112
163
  created,
113
164
  tools,
165
+ origin,
166
+ surface,
114
167
  body,
115
168
  };
116
169
  }
@@ -121,6 +174,16 @@ function formatFrontmatterValue(value) {
121
174
  return `[${value.join(", ")}]`;
122
175
  return String(value);
123
176
  }
177
+ function renderFrontmatterLine(lines, key, value) {
178
+ if (value && typeof value === "object" && !Array.isArray(value)) {
179
+ lines.push(`${key}:`);
180
+ for (const [childKey, childValue] of Object.entries(value)) {
181
+ lines.push(` ${childKey}: ${formatFrontmatterValue(childValue)}`);
182
+ }
183
+ return;
184
+ }
185
+ lines.push(`${key}: ${formatFrontmatterValue(value)}`);
186
+ }
124
187
  function renderHabitFile(frontmatter, body) {
125
188
  (0, runtime_1.emitNervesEvent)({
126
189
  event: "daemon.habit_render",
@@ -130,7 +193,7 @@ function renderHabitFile(frontmatter, body) {
130
193
  });
131
194
  const lines = ["---"];
132
195
  for (const key of Object.keys(frontmatter)) {
133
- lines.push(`${key}: ${formatFrontmatterValue(frontmatter[key])}`);
196
+ renderFrontmatterLine(lines, key, frontmatter[key]);
134
197
  }
135
198
  lines.push("---");
136
199
  lines.push("");
@@ -44,6 +44,8 @@ const runtime_1 = require("../../nerves/runtime");
44
44
  const auth_flow_1 = require("../auth/auth-flow");
45
45
  const provider_models_1 = require("../provider-models");
46
46
  const habit_parser_1 = require("../habits/habit-parser");
47
+ const bundle_manifest_1 = require("../../mind/bundle-manifest");
48
+ const record_paths_1 = require("../../mind/record-paths");
47
49
  const hatch_specialist_1 = require("./hatch-specialist");
48
50
  function requiredCredentialKeys(provider) {
49
51
  return identity_1.PROVIDER_CREDENTIALS[provider].required;
@@ -83,7 +85,7 @@ function writeHeartbeatHabit(bundleRoot, now) {
83
85
  cadence: "30m",
84
86
  status: "active",
85
87
  created: now.toISOString(),
86
- }, "Run a lightweight heartbeat cycle. Review task board and inbox.\nCheck on pending obligations. Journal anything important.");
88
+ }, "Run a lightweight heartbeat cycle. Review task board and inbox.\nCheck on pending obligations. Write important durable outputs to Arc or Desk record.");
87
89
  fs.writeFileSync(filePath, content, "utf-8");
88
90
  }
89
91
  function writeFriendImprint(bundleRoot, humanName, now) {
@@ -115,12 +117,15 @@ function writeFriendImprint(bundleRoot, humanName, now) {
115
117
  };
116
118
  fs.writeFileSync(path.join(friendsDir, `${id}.json`), `${JSON.stringify(record, null, 2)}\n`, "utf-8");
117
119
  }
118
- function writeDiaryScaffold(bundleRoot) {
119
- const diaryRoot = path.join(bundleRoot, "diary");
120
- fs.mkdirSync(path.join(diaryRoot, "daily"), { recursive: true });
121
- fs.mkdirSync(path.join(diaryRoot, "archive"), { recursive: true });
122
- fs.writeFileSync(path.join(diaryRoot, "facts.jsonl"), "", "utf-8");
123
- fs.writeFileSync(path.join(diaryRoot, "entities.json"), "{}\n", "utf-8");
120
+ function writeRecordScaffold(bundleRoot) {
121
+ const recordPaths = (0, record_paths_1.resolveDeskRecordPaths)(bundleRoot);
122
+ fs.mkdirSync(recordPaths.diaryDailyDir, { recursive: true });
123
+ fs.mkdirSync(recordPaths.notesRoot, { recursive: true });
124
+ fs.writeFileSync(recordPaths.factsPath, "", "utf-8");
125
+ fs.writeFileSync(recordPaths.entitiesPath, "{}\n", "utf-8");
126
+ fs.mkdirSync(path.join(bundleRoot, "arc", "flight-recorder", "events"), { recursive: true });
127
+ fs.mkdirSync(path.join(bundleRoot, "arc", "flight-recorder", "habit-receipts"), { recursive: true });
128
+ fs.mkdirSync(path.join(bundleRoot, "arc", "claims"), { recursive: true });
124
129
  }
125
130
  function writeHatchlingAgentConfig(bundleRoot, input) {
126
131
  const template = (0, identity_1.buildDefaultAgentTemplate)(input.agentName);
@@ -156,7 +161,9 @@ async function runHatchFlow(input, deps = {}) {
156
161
  fs.mkdirSync(bundleRoot, { recursive: true });
157
162
  writeReadme(bundleRoot, "Root of this agent bundle.");
158
163
  writeReadme(path.join(bundleRoot, "psyche"), "Identity and behavior files.");
159
- writeReadme(path.join(bundleRoot, "diary"), "Persistent diary -- things I have learned and chosen to keep.");
164
+ writeReadme(path.join(bundleRoot, "arc"), "Live continuity, claims, obligations, and resume state.");
165
+ writeReadme(path.join(bundleRoot, "desk"), "Durable work and maintained record.");
166
+ writeReadme(path.join(bundleRoot, "desk", "_record"), "Desk record: diary facts and maintained reference notes.");
160
167
  writeReadme(path.join(bundleRoot, "friends"), "Known friend records.");
161
168
  writeReadme(path.join(bundleRoot, "tasks"), "Task files.");
162
169
  writeReadme(path.join(bundleRoot, "tasks", "one-shots"), "One-shot tasks.");
@@ -166,8 +173,9 @@ async function runHatchFlow(input, deps = {}) {
166
173
  writeReadme(path.join(bundleRoot, "senses"), "Sense-specific config.");
167
174
  writeReadme(path.join(bundleRoot, "senses", "teams"), "Teams sense config.");
168
175
  writeHatchlingAgentConfig(bundleRoot, input);
176
+ fs.writeFileSync(path.join(bundleRoot, "bundle-meta.json"), `${JSON.stringify((0, bundle_manifest_1.createBundleMeta)(), null, 2)}\n`, "utf-8");
169
177
  const credentialPath = await storeHatchlingProviderCredentials(input.agentName, input.provider, input.credentials);
170
- writeDiaryScaffold(bundleRoot);
178
+ writeRecordScaffold(bundleRoot);
171
179
  writeFriendImprint(bundleRoot, input.humanName, now);
172
180
  writeHeartbeatHabit(bundleRoot, now);
173
181
  (0, runtime_1.emitNervesEvent)({
@@ -41,6 +41,7 @@ const tools_base_1 = require("../../repertoire/tools-base");
41
41
  const hatch_flow_1 = require("./hatch-flow");
42
42
  const hatch_animation_1 = require("./hatch-animation");
43
43
  const bundle_manifest_1 = require("../../mind/bundle-manifest");
44
+ const record_paths_1 = require("../../mind/record-paths");
44
45
  const identity_1 = require("../identity");
45
46
  const runtime_1 = require("../../nerves/runtime");
46
47
  const vault_setup_1 = require("../../repertoire/vault-setup");
@@ -107,9 +108,10 @@ function writeReadme(dir, purpose) {
107
108
  }
108
109
  }
109
110
  function scaffoldBundle(bundleRoot) {
110
- writeReadme(path.join(bundleRoot, "notes"), "Persistent notes store.");
111
- writeReadme(path.join(bundleRoot, "notes", "daily"), "Daily note entries.");
112
- writeReadme(path.join(bundleRoot, "notes", "archive"), "Archived notes.");
111
+ writeReadme(path.join(bundleRoot, "arc"), "Live continuity, claims, obligations, and resume state.");
112
+ writeReadme(path.join(bundleRoot, "arc", "flight-recorder"), "Flight recorder resume and event receipts.");
113
+ writeReadme(path.join(bundleRoot, "desk"), "Durable work and maintained record.");
114
+ writeReadme(path.join(bundleRoot, "desk", "_record"), "Desk record: diary facts and maintained reference notes.");
113
115
  writeReadme(path.join(bundleRoot, "friends"), "Known friend records.");
114
116
  writeReadme(path.join(bundleRoot, "tasks"), "Task files.");
115
117
  writeReadme(path.join(bundleRoot, "tasks", "one-shots"), "One-shot tasks.");
@@ -118,16 +120,18 @@ function scaffoldBundle(bundleRoot) {
118
120
  writeReadme(path.join(bundleRoot, "skills"), "Local skill files.");
119
121
  writeReadme(path.join(bundleRoot, "senses"), "Sense-specific config.");
120
122
  writeReadme(path.join(bundleRoot, "senses", "teams"), "Teams sense config.");
121
- // Notes scaffold files
122
- const notesRoot = path.join(bundleRoot, "notes");
123
- const factsPath = path.join(notesRoot, "facts.jsonl");
124
- const entitiesPath = path.join(notesRoot, "entities.json");
123
+ const recordPaths = (0, record_paths_1.resolveDeskRecordPaths)(bundleRoot);
124
+ fs.mkdirSync(recordPaths.diaryDailyDir, { recursive: true });
125
+ fs.mkdirSync(recordPaths.notesRoot, { recursive: true });
125
126
  /* v8 ignore next -- defensive: guard against re-scaffold on existing bundle @preserve */
126
- if (!fs.existsSync(factsPath))
127
- fs.writeFileSync(factsPath, "", "utf-8");
127
+ if (!fs.existsSync(recordPaths.factsPath))
128
+ fs.writeFileSync(recordPaths.factsPath, "", "utf-8");
128
129
  /* v8 ignore next -- defensive: guard against re-scaffold on existing bundle @preserve */
129
- if (!fs.existsSync(entitiesPath))
130
- fs.writeFileSync(entitiesPath, "{}\n", "utf-8");
130
+ if (!fs.existsSync(recordPaths.entitiesPath))
131
+ fs.writeFileSync(recordPaths.entitiesPath, "{}\n", "utf-8");
132
+ fs.mkdirSync(path.join(bundleRoot, "arc", "flight-recorder", "events"), { recursive: true });
133
+ fs.mkdirSync(path.join(bundleRoot, "arc", "flight-recorder", "habit-receipts"), { recursive: true });
134
+ fs.mkdirSync(path.join(bundleRoot, "arc", "claims"), { recursive: true });
131
135
  // bundle-meta.json
132
136
  const meta = (0, bundle_manifest_1.createBundleMeta)();
133
137
  fs.writeFileSync(path.join(bundleRoot, "bundle-meta.json"), JSON.stringify(meta, null, 2) + "\n", "utf-8");
@@ -138,6 +138,7 @@ exports.DEFAULT_AGENT_SENSES = {
138
138
  mail: { enabled: false },
139
139
  voice: { enabled: false },
140
140
  a2a: { enabled: false },
141
+ workbench: { enabled: false },
141
142
  };
142
143
  function normalizeSenses(value, configFile) {
143
144
  const defaults = {
@@ -147,6 +148,7 @@ function normalizeSenses(value, configFile) {
147
148
  mail: { ...exports.DEFAULT_AGENT_SENSES.mail },
148
149
  voice: { ...exports.DEFAULT_AGENT_SENSES.voice },
149
150
  a2a: { ...exports.DEFAULT_AGENT_SENSES.a2a },
151
+ workbench: { ...exports.DEFAULT_AGENT_SENSES.workbench },
150
152
  };
151
153
  if (value === undefined) {
152
154
  return defaults;
@@ -162,7 +164,7 @@ function normalizeSenses(value, configFile) {
162
164
  throw new Error(`agent.json at ${configFile} must include senses as an object when present.`);
163
165
  }
164
166
  const raw = value;
165
- const senseNames = ["cli", "teams", "bluebubbles", "mail", "voice", "a2a"];
167
+ const senseNames = ["cli", "teams", "bluebubbles", "mail", "voice", "a2a", "workbench"];
166
168
  for (const senseName of senseNames) {
167
169
  const rawSense = raw[senseName];
168
170
  if (rawSense === undefined) {
@@ -207,6 +209,7 @@ function buildDefaultAgentTemplate(_agentName) {
207
209
  mail: { ...exports.DEFAULT_AGENT_SENSES.mail },
208
210
  voice: { ...exports.DEFAULT_AGENT_SENSES.voice },
209
211
  a2a: { ...exports.DEFAULT_AGENT_SENSES.a2a },
212
+ workbench: { ...exports.DEFAULT_AGENT_SENSES.workbench },
210
213
  },
211
214
  phrases: {
212
215
  thinking: [...exports.DEFAULT_AGENT_PHRASES.thinking],
@@ -1,44 +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.gatherKeptNotesCandidates = gatherKeptNotesCandidates;
37
4
  exports.renderKeptNotesOutcome = renderKeptNotesOutcome;
38
5
  exports.injectKeptNotes = injectKeptNotes;
39
6
  exports.createKeptNotesJudge = createKeptNotesJudge;
40
- const fs = __importStar(require("fs"));
41
- const path = __importStar(require("path"));
42
7
  const diary_1 = require("../mind/diary");
43
8
  const runtime_1 = require("../nerves/runtime");
44
9
  const DEFAULT_TIMEOUT_MS = 2500;
@@ -82,26 +47,6 @@ function scoreText(queryTerms, text) {
82
47
  }
83
48
  return matches / queryTerms.size;
84
49
  }
85
- function readJournalIndex(journalDir) {
86
- try {
87
- const parsed = JSON.parse(fs.readFileSync(path.join(journalDir, ".index.json"), "utf8"));
88
- if (!Array.isArray(parsed))
89
- return [];
90
- return parsed
91
- .filter((entry) => (typeof entry === "object" &&
92
- entry !== null &&
93
- typeof entry.filename === "string" &&
94
- typeof entry.preview === "string"));
95
- }
96
- catch {
97
- return [];
98
- }
99
- }
100
- function journalDirForDiaryRoot(diaryRoot, explicitJournalDir) {
101
- if (explicitJournalDir)
102
- return explicitJournalDir;
103
- return path.join(path.dirname(diaryRoot), "journal");
104
- }
105
50
  function diaryCandidate(fact) {
106
51
  return {
107
52
  text: fact.text,
@@ -133,17 +78,7 @@ function gatherKeptNotesCandidates(query, options = {}) {
133
78
  const diaryCandidates = diaryEntries
134
79
  .map((fact) => ({ candidate: diaryCandidate(fact), score: scoreText(queryTerms, fact.text) }))
135
80
  .filter((entry) => entry.score > 0);
136
- const journalDir = journalDirForDiaryRoot(diaryRoot, options.journalDir);
137
- const journalCandidates = readJournalIndex(journalDir)
138
- .map((entry) => ({
139
- candidate: {
140
- text: `${entry.filename}: ${entry.preview}`,
141
- source: { kind: "journal", label: "journal", ref: entry.filename },
142
- },
143
- score: scoreText(queryTerms, `${entry.filename} ${entry.preview}`),
144
- }))
145
- .filter((entry) => entry.score > 0);
146
- return [...diaryCandidates, ...journalCandidates, ...friendNoteCandidates(options.friend, queryTerms)]
81
+ return [...diaryCandidates, ...friendNoteCandidates(options.friend, queryTerms)]
147
82
  .sort((left, right) => right.score - left.score)
148
83
  .slice(0, MAX_CANDIDATES)
149
84
  .map((entry) => entry.candidate);
@@ -176,18 +111,15 @@ function fuzzyLine(text) {
176
111
  return trimmed;
177
112
  return `I may have kept something related: ${trimmed}`;
178
113
  }
179
- const SOURCE_KIND_ORDER = ["diary", "journal", "friend-note"];
114
+ const SOURCE_KIND_ORDER = ["diary", "friend-note"];
180
115
  const SOURCE_KIND_LABELS = {
181
- diary: "my diary",
182
- journal: "my journal",
116
+ diary: "my Desk record diary",
183
117
  "friend-note": "my friend notes",
184
118
  };
185
119
  function joinLabels(labels) {
186
120
  if (labels.length === 1)
187
121
  return labels[0];
188
- if (labels.length === 2)
189
- return `${labels[0]} and ${labels[1]}`;
190
- return `${labels.slice(0, -1).join(", ")}, and ${labels[labels.length - 1]}`;
122
+ return `${labels[0]} and ${labels[1]}`;
191
123
  }
192
124
  function sourceHeading(sources) {
193
125
  const sourceKinds = new Set(sources.map((source) => source.kind));
@@ -195,7 +127,7 @@ function sourceHeading(sources) {
195
127
  .filter((kind) => sourceKinds.has(kind))
196
128
  .map((kind) => SOURCE_KIND_LABELS[kind]);
197
129
  if (labels.length === 0)
198
- return "## from notes i chose to keep";
130
+ return "## from my kept record";
199
131
  return `## from ${joinLabels(labels)}`;
200
132
  }
201
133
  function renderKeptNotesOutcome(outcome) {
@@ -53,6 +53,7 @@ const daemon_health_1 = require("../../daemon/daemon-health");
53
53
  const shared_1 = require("./shared");
54
54
  const agent_machine_1 = require("./agent-machine");
55
55
  const sessions_1 = require("./sessions");
56
+ const record_paths_1 = require("../../../mind/record-paths");
56
57
  const NOTES_VIEW_LIMIT = 20;
57
58
  /* v8 ignore start — defensive parsing of on-disk JSON, fallback branches are safety nets */
58
59
  function readCodingDeep(agentRoot) {
@@ -324,71 +325,42 @@ function readDaemonHealthDeep(healthPath) {
324
325
  }
325
326
  /* v8 ignore stop */
326
327
  function readNotesView(agentRoot) {
327
- const diaryRoot = path.join(agentRoot, "diary");
328
- const effectiveDiaryRoot = fs.existsSync(diaryRoot) ? diaryRoot : null;
328
+ const recordPaths = (0, record_paths_1.resolveDeskRecordPaths)(agentRoot);
329
329
  const diaryEntries = [];
330
- if (effectiveDiaryRoot) {
331
- const factsPath = path.join(effectiveDiaryRoot, "facts.jsonl");
332
- try {
333
- const raw = fs.readFileSync(factsPath, "utf-8");
334
- for (const line of raw.split("\n")) {
335
- if (!line.trim())
336
- continue;
337
- try {
338
- const entry = JSON.parse(line);
339
- if (typeof entry.id === "string" && typeof entry.text === "string") {
340
- diaryEntries.push({
341
- id: entry.id,
342
- text: entry.text,
343
- source: typeof entry.source === "string" ? entry.source : "",
344
- createdAt: typeof entry.createdAt === "string" ? entry.createdAt : "",
345
- });
346
- }
347
- }
348
- catch {
349
- // skip unparseable lines
350
- }
351
- }
352
- }
353
- catch {
354
- // no diary facts file
355
- }
356
- }
357
- diaryEntries.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
358
- const journalDir = path.join(agentRoot, "journal");
359
- const journalEntries = [];
360
- const indexPath = path.join(journalDir, ".index.json");
361
330
  try {
362
- const raw = fs.readFileSync(indexPath, "utf-8");
363
- const index = JSON.parse(raw);
364
- if (Array.isArray(index)) {
365
- for (const entry of index) {
366
- if (typeof entry.filename === "string") {
367
- journalEntries.push({
368
- filename: entry.filename,
369
- preview: typeof entry.preview === "string" ? entry.preview : "",
370
- mtime: typeof entry.mtime === "number" ? entry.mtime : 0,
331
+ const raw = fs.readFileSync(recordPaths.factsPath, "utf-8");
332
+ for (const line of raw.split("\n")) {
333
+ if (!line.trim())
334
+ continue;
335
+ try {
336
+ const entry = JSON.parse(line);
337
+ if (typeof entry.id === "string" && typeof entry.text === "string") {
338
+ diaryEntries.push({
339
+ id: entry.id,
340
+ text: entry.text,
341
+ source: typeof entry.source === "string" ? entry.source : "",
342
+ createdAt: typeof entry.createdAt === "string" ? entry.createdAt : "",
371
343
  });
372
344
  }
373
345
  }
346
+ catch {
347
+ // skip unparseable lines
348
+ }
374
349
  }
375
350
  }
376
351
  catch {
377
- // no journal index
352
+ // no diary facts file
378
353
  }
379
- journalEntries.sort((a, b) => b.mtime - a.mtime);
380
- const canonicalNotes = readCanonicalNotes(agentRoot);
354
+ diaryEntries.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
355
+ const canonicalNotes = readCanonicalNotes(recordPaths.notesRoot);
381
356
  return {
382
357
  diaryEntryCount: diaryEntries.length,
383
358
  recentDiaryEntries: diaryEntries.slice(0, NOTES_VIEW_LIMIT),
384
- journalEntryCount: journalEntries.length,
385
- recentJournalEntries: journalEntries.slice(0, NOTES_VIEW_LIMIT),
386
359
  canonicalNoteCount: canonicalNotes.length,
387
360
  recentCanonicalNotes: canonicalNotes.slice(0, NOTES_VIEW_LIMIT),
388
361
  };
389
362
  }
390
- function readCanonicalNotes(agentRoot) {
391
- const notesRoot = path.join(agentRoot, "notes");
363
+ function readCanonicalNotes(notesRoot) {
392
364
  const notes = [];
393
365
  for (const filename of (0, shared_1.safeReaddir)(notesRoot)) {
394
366
  if (!filename.endsWith(".md"))
@@ -123,7 +123,7 @@ const TOOL_TO_COMMAND = {
123
123
  status: "agent.status",
124
124
  catchup: "agent.catchup",
125
125
  get_context: "agent.getContext",
126
- search_notes: "agent.searchNotes",
126
+ search_facts: "agent.searchFacts",
127
127
  get_task: "agent.getTask",
128
128
  };
129
129
  const UUID_PREFIX_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-/i;
@@ -326,7 +326,7 @@ function createMcpServer(options) {
326
326
  status: "handleAgentStatus",
327
327
  catchup: "handleAgentCatchup",
328
328
  get_context: "handleAgentGetContext",
329
- search_notes: "handleAgentSearchNotes",
329
+ search_facts: "handleAgentSearchFacts",
330
330
  get_task: "handleAgentGetTask",
331
331
  };
332
332
  function stringArg(args, key) {
@@ -537,7 +537,7 @@ function getToolSchemas() {
537
537
  return [
538
538
  {
539
539
  name: "ask",
540
- description: "Ask the agent a question through a full conversation turn. This has the same identity, tools, and session continuity as send_message; use search_notes for read-only note lookup.",
540
+ description: "Ask the agent a question through a full conversation turn. This has the same identity, tools, and session continuity as send_message; use search_facts or consult_notes for read-only record lookup.",
541
541
  inputSchema: {
542
542
  type: "object",
543
543
  properties: {
@@ -548,7 +548,7 @@ function getToolSchemas() {
548
548
  },
549
549
  {
550
550
  name: "status",
551
- description: "Get the agent's current status including active sessions, diary and journal state, and activity level.",
551
+ description: "Get the agent's current status including active sessions, Desk record state, and activity level.",
552
552
  inputSchema: {
553
553
  type: "object",
554
554
  properties: {},
@@ -576,19 +576,19 @@ function getToolSchemas() {
576
576
  },
577
577
  {
578
578
  name: "get_context",
579
- description: "Get the agent's current working context including note summary, active tasks, and relevant state.",
579
+ description: "Get the agent's current working context including Desk record summary, active tasks, and relevant state.",
580
580
  inputSchema: {
581
581
  type: "object",
582
582
  properties: {},
583
583
  },
584
584
  },
585
585
  {
586
- name: "search_notes",
587
- description: "Read-only note search. Returns matching diary lines without running an agent turn or treating missing matches as absence of agent belief.",
586
+ name: "search_facts",
587
+ description: "Read-only fact search. Returns matching Desk record diary lines without running an agent turn or treating missing matches as absence of agent belief.",
588
588
  inputSchema: {
589
589
  type: "object",
590
590
  properties: {
591
- query: { type: "string", description: "Search term to look for in agent notes" },
591
+ query: { type: "string", description: "Search term to look for in agent facts" },
592
592
  },
593
593
  required: ["query"],
594
594
  },
@@ -10,6 +10,7 @@ const SENSES = [
10
10
  { sense: "mail", label: "Mail", daemonManaged: true },
11
11
  { sense: "voice", label: "Voice", daemonManaged: true },
12
12
  { sense: "a2a", label: "A2A", daemonManaged: true },
13
+ { sense: "workbench", label: "Workbench", daemonManaged: false },
13
14
  ];
14
15
  function configuredSenses(senses) {
15
16
  const configured = senses ?? {};
@@ -21,6 +22,7 @@ function configuredSenses(senses) {
21
22
  mail: configured.mail ?? { ...identity_1.DEFAULT_AGENT_SENSES.mail },
22
23
  voice: configured.voice ?? { ...identity_1.DEFAULT_AGENT_SENSES.voice },
23
24
  a2a: configured.a2a ?? { ...identity_1.DEFAULT_AGENT_SENSES.a2a },
25
+ workbench: configured.workbench ?? { ...identity_1.DEFAULT_AGENT_SENSES.workbench },
24
26
  };
25
27
  }
26
28
  function resolveStatus(enabled, daemonManaged, runtimeInfo) {