@ouro.bot/cli 0.1.0-alpha.183 → 0.1.0-alpha.185

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/changelog.json CHANGED
@@ -1,6 +1,21 @@
1
1
  {
2
2
  "_note": "This changelog is maintained as part of the PR/version-bump workflow. Agent-curated, not auto-generated. Agents read this file directly via read_file to understand what changed between versions.",
3
3
  "versions": [
4
+ {
5
+ "version": "0.1.0-alpha.185",
6
+ "changes": [
7
+ "fix(hatch): pass model name to adoption specialist from discovered credentials",
8
+ "feat(continuity): wake packets, episodes, cares, intentions, peer presence, and temporal self",
9
+ "fix(continuity): deduplicate obligations in prompt, keep session summary, pass preloaded data",
10
+ "feat(continuity): 9 new modules — episodes, cares, agent-relationships, intentions, presence, tempo, temporal-view, wake-packet, obligation enrichment",
11
+ "feat(continuity): 8 new tools — query_episodes, capture_episode, query_presence, query_cares, care_manage, query_relationships, intention_capture, intention_manage",
12
+ "feat(continuity): 3-layer architecture — durable state, derived views, surfaces",
13
+ "feat(pipeline): continuity threading — tempo derivation, wake packet assembly, presence update, episode emission on every turn",
14
+ "feat(prompt): wake packet prompt section with token budget and truncation priority",
15
+ "feat(coding): coding context receives compact wake packet, coding completion emits episodes",
16
+ "feat(outlook): expose continuity data (presence, cares, episodes) to outlook surfaces"
17
+ ]
18
+ },
4
19
  {
5
20
  "version": "0.1.0-alpha.183",
6
21
  "changes": [
@@ -469,7 +469,7 @@ function buildActiveWorkFrame(input) {
469
469
  });
470
470
  return frame;
471
471
  }
472
- function formatActiveWorkFrame(frame) {
472
+ function formatActiveWorkFrame(frame, options) {
473
473
  const lines = ["## what i'm holding"];
474
474
  lines.push("this is my top-level live world-state right now. inner work, coding lanes, other sessions, and return obligations all belong inside this picture.");
475
475
  lines.push("if older checkpoints elsewhere in the transcript disagree with this picture, this picture wins.");
@@ -577,16 +577,25 @@ function formatActiveWorkFrame(frame) {
577
577
  lines.push(targetCandidatesBlock);
578
578
  }
579
579
  if ((frame.pendingObligations ?? []).length > 0) {
580
- lines.push("");
581
- lines.push("## return obligations");
582
- for (const obligation of frame.pendingObligations) {
583
- if (!(0, obligations_1.isOpenObligationStatus)(obligation.status))
584
- continue;
585
- let obligationLine = `- [${obligation.status}] ${obligation.origin.friendId}/${obligation.origin.channel}/${obligation.origin.key}: ${obligation.content}${formatObligationSurface(obligation)}`;
586
- if (obligation.latestNote?.trim()) {
587
- obligationLine += `\n latest: ${obligation.latestNote.trim()}`;
580
+ const openCount = frame.pendingObligations.filter((ob) => (0, obligations_1.isOpenObligationStatus)(ob.status)).length;
581
+ if (options?.hasWakePacket && openCount > 0) {
582
+ // Wake packet carries enriched obligations (with resumeHint, stalenessClass, waitingOn).
583
+ // Avoid duplicating the full list — just anchor the count here.
584
+ lines.push("");
585
+ lines.push(`return obligations: ${openCount} active (canonical details in **Owed** section of wake packet)`);
586
+ }
587
+ else if (openCount > 0) {
588
+ lines.push("");
589
+ lines.push("## return obligations");
590
+ for (const obligation of frame.pendingObligations) {
591
+ if (!(0, obligations_1.isOpenObligationStatus)(obligation.status))
592
+ continue;
593
+ let obligationLine = `- [${obligation.status}] ${obligation.origin.friendId}/${obligation.origin.channel}/${obligation.origin.key}: ${obligation.content}${formatObligationSurface(obligation)}`;
594
+ if (obligation.latestNote?.trim()) {
595
+ obligationLine += `\n latest: ${obligation.latestNote.trim()}`;
596
+ }
597
+ lines.push(obligationLine);
588
598
  }
589
- lines.push(obligationLine);
590
599
  }
591
600
  }
592
601
  if (frame.innerReturnObligations && frame.innerReturnObligations.length > 0) {
@@ -0,0 +1,161 @@
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.recordInteraction = recordInteraction;
37
+ exports.readRelationships = readRelationships;
38
+ exports.readRelationship = readRelationship;
39
+ exports.recordOutcome = recordOutcome;
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ const runtime_1 = require("../nerves/runtime");
43
+ function relationshipsDir(agentRoot) {
44
+ return path.join(agentRoot, "state", "relationships");
45
+ }
46
+ function relationshipFilePath(agentRoot, agentName) {
47
+ return path.join(relationshipsDir(agentRoot), `${agentName.toLowerCase()}.json`);
48
+ }
49
+ function readRelationshipFile(agentRoot, agentName) {
50
+ const filePath = relationshipFilePath(agentRoot, agentName);
51
+ if (!fs.existsSync(filePath)) {
52
+ return null;
53
+ }
54
+ return JSON.parse(fs.readFileSync(filePath, "utf-8"));
55
+ }
56
+ function writeRelationshipFile(agentRoot, rel) {
57
+ const dir = relationshipsDir(agentRoot);
58
+ fs.mkdirSync(dir, { recursive: true });
59
+ fs.writeFileSync(path.join(dir, `${rel.agentName}.json`), JSON.stringify(rel, null, 2), "utf-8");
60
+ }
61
+ function recordInteraction(agentRoot, agentName, context) {
62
+ const normalizedName = agentName.toLowerCase();
63
+ const now = new Date().toISOString();
64
+ const existing = readRelationshipFile(agentRoot, normalizedName);
65
+ if (existing) {
66
+ existing.familiarity += 1;
67
+ existing.lastInteraction = now;
68
+ if (context.displayName) {
69
+ existing.displayName = context.displayName;
70
+ }
71
+ if (context.missionId && !existing.sharedMissions.includes(context.missionId)) {
72
+ existing.sharedMissions.push(context.missionId);
73
+ }
74
+ if (context.note) {
75
+ existing.notes.push(context.note);
76
+ }
77
+ writeRelationshipFile(agentRoot, existing);
78
+ (0, runtime_1.emitNervesEvent)({
79
+ component: "heart",
80
+ event: "heart.relationship_updated",
81
+ message: `relationship updated: ${normalizedName}`,
82
+ meta: { agentName: normalizedName, familiarity: existing.familiarity },
83
+ });
84
+ return existing;
85
+ }
86
+ const rel = {
87
+ agentName: normalizedName,
88
+ displayName: context.displayName ?? normalizedName,
89
+ familiarity: 1,
90
+ trust: "neutral",
91
+ sharedMissions: context.missionId ? [context.missionId] : [],
92
+ lastInteraction: now,
93
+ outcomes: [],
94
+ notes: context.note ? [context.note] : [],
95
+ };
96
+ writeRelationshipFile(agentRoot, rel);
97
+ (0, runtime_1.emitNervesEvent)({
98
+ component: "heart",
99
+ event: "heart.relationship_created",
100
+ message: `relationship created: ${normalizedName}`,
101
+ meta: { agentName: normalizedName },
102
+ });
103
+ return rel;
104
+ }
105
+ function readRelationships(agentRoot) {
106
+ const dir = relationshipsDir(agentRoot);
107
+ if (!fs.existsSync(dir)) {
108
+ (0, runtime_1.emitNervesEvent)({
109
+ component: "heart",
110
+ event: "heart.relationships_read",
111
+ message: "read relationships: directory missing, returning empty",
112
+ meta: { count: 0 },
113
+ });
114
+ return [];
115
+ }
116
+ const files = fs.readdirSync(dir).filter((f) => f.endsWith(".json"));
117
+ const relationships = [];
118
+ for (const file of files) {
119
+ try {
120
+ const content = fs.readFileSync(path.join(dir, file), "utf-8");
121
+ const rel = JSON.parse(content);
122
+ relationships.push(rel);
123
+ }
124
+ catch {
125
+ // Skip malformed JSON files
126
+ }
127
+ }
128
+ (0, runtime_1.emitNervesEvent)({
129
+ component: "heart",
130
+ event: "heart.relationships_read",
131
+ message: `read ${relationships.length} relationships`,
132
+ meta: { count: relationships.length },
133
+ });
134
+ return relationships;
135
+ }
136
+ function readRelationship(agentRoot, agentName) {
137
+ const rel = readRelationshipFile(agentRoot, agentName);
138
+ (0, runtime_1.emitNervesEvent)({
139
+ component: "heart",
140
+ event: "heart.relationship_read",
141
+ message: rel ? `read relationship: ${agentName.toLowerCase()}` : `relationship not found: ${agentName.toLowerCase()}`,
142
+ meta: { agentName: agentName.toLowerCase(), found: !!rel },
143
+ });
144
+ return rel;
145
+ }
146
+ function recordOutcome(agentRoot, agentName, outcome) {
147
+ const normalizedName = agentName.toLowerCase();
148
+ const existing = readRelationshipFile(agentRoot, normalizedName);
149
+ if (!existing) {
150
+ throw new Error(`Agent relationship not found: ${normalizedName}`);
151
+ }
152
+ existing.outcomes.push(outcome);
153
+ writeRelationshipFile(agentRoot, existing);
154
+ (0, runtime_1.emitNervesEvent)({
155
+ component: "heart",
156
+ event: "heart.outcome_recorded",
157
+ message: `outcome recorded for ${normalizedName}: ${outcome.result}`,
158
+ meta: { agentName: normalizedName, missionId: outcome.missionId, result: outcome.result },
159
+ });
160
+ return existing;
161
+ }
@@ -0,0 +1,174 @@
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.createCare = createCare;
37
+ exports.readCares = readCares;
38
+ exports.readActiveCares = readActiveCares;
39
+ exports.updateCare = updateCare;
40
+ exports.resolveCare = resolveCare;
41
+ const fs = __importStar(require("fs"));
42
+ const path = __importStar(require("path"));
43
+ const runtime_1 = require("../nerves/runtime");
44
+ function caresDir(agentRoot) {
45
+ return path.join(agentRoot, "state", "cares");
46
+ }
47
+ function careFilePath(agentRoot, id) {
48
+ return path.join(caresDir(agentRoot), `${id}.json`);
49
+ }
50
+ function generateId() {
51
+ const timestamp = Date.now();
52
+ const random = Math.random().toString(36).slice(2, 10);
53
+ return `care-${timestamp}-${random}`;
54
+ }
55
+ function createCare(agentRoot, input) {
56
+ const now = new Date().toISOString();
57
+ const id = generateId();
58
+ const care = {
59
+ id,
60
+ label: input.label,
61
+ why: input.why,
62
+ kind: input.kind,
63
+ status: input.status,
64
+ salience: input.salience,
65
+ steward: input.steward,
66
+ relatedFriendIds: input.relatedFriendIds,
67
+ relatedAgentIds: input.relatedAgentIds,
68
+ relatedObligationIds: input.relatedObligationIds,
69
+ relatedEpisodeIds: input.relatedEpisodeIds,
70
+ currentRisk: input.currentRisk,
71
+ nextCheckAt: input.nextCheckAt,
72
+ createdAt: now,
73
+ updatedAt: now,
74
+ };
75
+ const dir = caresDir(agentRoot);
76
+ fs.mkdirSync(dir, { recursive: true });
77
+ fs.writeFileSync(careFilePath(agentRoot, id), JSON.stringify(care, null, 2), "utf-8");
78
+ (0, runtime_1.emitNervesEvent)({
79
+ component: "heart",
80
+ event: "heart.care_created",
81
+ message: `care created: ${input.label}`,
82
+ meta: { careId: id, status: input.status, salience: input.salience },
83
+ });
84
+ return care;
85
+ }
86
+ function readCares(agentRoot) {
87
+ const dir = caresDir(agentRoot);
88
+ if (!fs.existsSync(dir)) {
89
+ (0, runtime_1.emitNervesEvent)({
90
+ component: "heart",
91
+ event: "heart.cares_read",
92
+ message: "read cares: directory missing, returning empty",
93
+ meta: { count: 0 },
94
+ });
95
+ return [];
96
+ }
97
+ const files = fs.readdirSync(dir).filter((f) => f.endsWith(".json"));
98
+ const cares = [];
99
+ for (const file of files) {
100
+ try {
101
+ const content = fs.readFileSync(path.join(dir, file), "utf-8");
102
+ const care = JSON.parse(content);
103
+ cares.push(care);
104
+ }
105
+ catch {
106
+ // Skip malformed JSON files gracefully
107
+ }
108
+ }
109
+ (0, runtime_1.emitNervesEvent)({
110
+ component: "heart",
111
+ event: "heart.cares_read",
112
+ message: `read ${cares.length} cares`,
113
+ meta: { count: cares.length },
114
+ });
115
+ return cares;
116
+ }
117
+ function readActiveCares(agentRoot) {
118
+ const all = readCares(agentRoot);
119
+ const active = all.filter((c) => c.status === "active" || c.status === "watching");
120
+ (0, runtime_1.emitNervesEvent)({
121
+ component: "heart",
122
+ event: "heart.active_cares_read",
123
+ message: `read ${active.length} active cares`,
124
+ meta: { count: active.length, total: all.length },
125
+ });
126
+ return active;
127
+ }
128
+ function readCareFile(agentRoot, id) {
129
+ const filePath = careFilePath(agentRoot, id);
130
+ if (!fs.existsSync(filePath)) {
131
+ throw new Error(`Care not found: ${id}`);
132
+ }
133
+ return JSON.parse(fs.readFileSync(filePath, "utf-8"));
134
+ }
135
+ function writeCareFile(agentRoot, care) {
136
+ fs.writeFileSync(careFilePath(agentRoot, care.id), JSON.stringify(care, null, 2), "utf-8");
137
+ }
138
+ function updateCare(agentRoot, id, updates) {
139
+ const care = readCareFile(agentRoot, id);
140
+ const now = new Date().toISOString();
141
+ const updated = {
142
+ ...care,
143
+ ...updates,
144
+ id: care.id, // protect ID from overwrite
145
+ createdAt: care.createdAt, // protect createdAt
146
+ updatedAt: now,
147
+ };
148
+ writeCareFile(agentRoot, updated);
149
+ (0, runtime_1.emitNervesEvent)({
150
+ component: "heart",
151
+ event: "heart.care_updated",
152
+ message: `care updated: ${updated.label}`,
153
+ meta: { careId: id, updates: Object.keys(updates) },
154
+ });
155
+ return updated;
156
+ }
157
+ function resolveCare(agentRoot, id) {
158
+ const care = readCareFile(agentRoot, id);
159
+ const now = new Date().toISOString();
160
+ const resolved = {
161
+ ...care,
162
+ status: "resolved",
163
+ resolvedAt: now,
164
+ updatedAt: now,
165
+ };
166
+ writeCareFile(agentRoot, resolved);
167
+ (0, runtime_1.emitNervesEvent)({
168
+ component: "heart",
169
+ event: "heart.care_resolved",
170
+ message: `care resolved: ${resolved.label}`,
171
+ meta: { careId: id },
172
+ });
173
+ return resolved;
174
+ }
@@ -1491,12 +1491,13 @@ async function defaultRunAdoptionSpecialist() {
1491
1491
  // Load identity-specific spinner phrases (falls back to DEFAULT_AGENT_PHRASES)
1492
1492
  const { loadIdentityPhrases } = await Promise.resolve().then(() => __importStar(require("./specialist-orchestrator")));
1493
1493
  const phrases = loadIdentityPhrases(bundleSourceDir, identity.fileName);
1494
+ const resolvedModel = providerConfig.model || providerConfig.deployment || "";
1494
1495
  setAgentConfigOverride({
1495
1496
  version: 2,
1496
1497
  enabled: true,
1497
1498
  provider: providerRaw,
1498
- humanFacing: { provider: providerRaw, model: "" },
1499
- agentFacing: { provider: providerRaw, model: "" },
1499
+ humanFacing: { provider: providerRaw, model: resolvedModel },
1500
+ agentFacing: { provider: providerRaw, model: resolvedModel },
1500
1501
  phrases,
1501
1502
  });
1502
1503
  patchRuntimeConfig({
@@ -47,6 +47,7 @@ exports.readLogView = readLogView;
47
47
  exports.readHabitView = readHabitView;
48
48
  exports.readNeedsMeView = readNeedsMeView;
49
49
  exports.readDeskPrefs = readDeskPrefs;
50
+ exports.readOutlookContinuity = readOutlookContinuity;
50
51
  const fs = __importStar(require("fs"));
51
52
  const path = __importStar(require("path"));
52
53
  const runtime_1 = require("../../nerves/runtime");
@@ -59,6 +60,9 @@ const agent_discovery_1 = require("./agent-discovery");
59
60
  const runtime_metadata_1 = require("./runtime-metadata");
60
61
  const thoughts_1 = require("./thoughts");
61
62
  const outlook_types_1 = require("./outlook-types");
63
+ const presence_1 = require("../presence");
64
+ const cares_1 = require("../cares");
65
+ const episodes_1 = require("../../mind/episodes");
62
66
  const LIVE_TASK_STATUSES = ["processing", "validating", "collaborating", "blocked"];
63
67
  const ACTIVE_CODING_STATUSES = new Set(["spawning", "running", "waiting_input", "stalled"]);
64
68
  const BLOCKED_CODING_STATUSES = new Set(["waiting_input", "stalled"]);
@@ -1289,3 +1293,39 @@ function parseCadenceMs(cadence) {
1289
1293
  /* v8 ignore next */
1290
1294
  return null;
1291
1295
  }
1296
+ // ---------------------------------------------------------------------------
1297
+ // Continuity — presence, cares, episodes for outlook surfaces
1298
+ // ---------------------------------------------------------------------------
1299
+ function readOutlookContinuity(agentRoot, agentName) {
1300
+ const self = (0, presence_1.readPresence)(agentRoot, agentName);
1301
+ const peers = (0, presence_1.readPeerPresence)(agentRoot);
1302
+ const cares = (0, cares_1.readActiveCares)(agentRoot);
1303
+ const episodes = (0, episodes_1.readRecentEpisodes)(agentRoot, { limit: 10 });
1304
+ (0, runtime_1.emitNervesEvent)({
1305
+ component: "heart",
1306
+ event: "heart.outlook_continuity_read",
1307
+ message: `outlook continuity: ${cares.length} cares, ${episodes.length} episodes`,
1308
+ meta: { careCount: cares.length, episodeCount: episodes.length, hasSelf: self != null, peerCount: peers.length },
1309
+ });
1310
+ return {
1311
+ presence: { self, peers },
1312
+ cares: {
1313
+ activeCount: cares.length,
1314
+ items: cares.map((c) => ({
1315
+ id: c.id,
1316
+ label: c.label,
1317
+ status: c.status,
1318
+ salience: c.salience,
1319
+ })),
1320
+ },
1321
+ episodes: {
1322
+ recentCount: episodes.length,
1323
+ items: episodes.map((ep) => ({
1324
+ id: ep.id,
1325
+ kind: ep.kind,
1326
+ summary: ep.summary,
1327
+ timestamp: ep.timestamp,
1328
+ })),
1329
+ },
1330
+ };
1331
+ }
@@ -0,0 +1,168 @@
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.captureIntention = captureIntention;
37
+ exports.readOpenIntentions = readOpenIntentions;
38
+ exports.resolveIntention = resolveIntention;
39
+ exports.dismissIntention = dismissIntention;
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ const runtime_1 = require("../nerves/runtime");
43
+ function intentionsDir(agentRoot) {
44
+ return path.join(agentRoot, "state", "intentions");
45
+ }
46
+ function intentionFilePath(agentRoot, id) {
47
+ return path.join(intentionsDir(agentRoot), `${id}.json`);
48
+ }
49
+ function generateId() {
50
+ const timestamp = Date.now();
51
+ const random = Math.random().toString(36).slice(2, 10);
52
+ return `int-${timestamp}-${random}`;
53
+ }
54
+ const SALIENCE_ORDER = {
55
+ high: 3,
56
+ medium: 2,
57
+ low: 1,
58
+ };
59
+ function salienceRank(salience) {
60
+ if (!salience)
61
+ return 0;
62
+ return SALIENCE_ORDER[salience] ?? 0;
63
+ }
64
+ function captureIntention(agentRoot, input) {
65
+ const now = new Date().toISOString();
66
+ const id = generateId();
67
+ const intention = {
68
+ id,
69
+ content: input.content,
70
+ status: "open",
71
+ createdAt: now,
72
+ updatedAt: now,
73
+ ...(input.salience ? { salience: input.salience } : {}),
74
+ source: input.source,
75
+ ...(input.relatedFriendId ? { relatedFriendId: input.relatedFriendId } : {}),
76
+ ...(input.relatedObligationId ? { relatedObligationId: input.relatedObligationId } : {}),
77
+ ...(input.relatedCareId ? { relatedCareId: input.relatedCareId } : {}),
78
+ ...(input.nudgeAfter ? { nudgeAfter: input.nudgeAfter } : {}),
79
+ };
80
+ const dir = intentionsDir(agentRoot);
81
+ fs.mkdirSync(dir, { recursive: true });
82
+ fs.writeFileSync(intentionFilePath(agentRoot, id), JSON.stringify(intention, null, 2), "utf-8");
83
+ (0, runtime_1.emitNervesEvent)({
84
+ component: "heart",
85
+ event: "heart.intention_captured",
86
+ message: `intention captured: ${input.content.slice(0, 60)}`,
87
+ meta: { intentionId: id, source: input.source, salience: input.salience },
88
+ });
89
+ return intention;
90
+ }
91
+ function readOpenIntentions(agentRoot, options) {
92
+ const dir = intentionsDir(agentRoot);
93
+ if (!fs.existsSync(dir)) {
94
+ (0, runtime_1.emitNervesEvent)({
95
+ component: "heart",
96
+ event: "heart.intentions_read",
97
+ message: "read intentions: directory missing, returning empty",
98
+ meta: { count: 0 },
99
+ });
100
+ return [];
101
+ }
102
+ const limit = options?.limit ?? 20;
103
+ const files = fs.readdirSync(dir).filter((f) => f.endsWith(".json"));
104
+ const intentions = [];
105
+ for (const file of files) {
106
+ try {
107
+ const content = fs.readFileSync(path.join(dir, file), "utf-8");
108
+ const intention = JSON.parse(content);
109
+ if (intention.status === "open") {
110
+ intentions.push(intention);
111
+ }
112
+ }
113
+ catch {
114
+ // Skip malformed JSON files
115
+ }
116
+ }
117
+ // Sort by salience descending, then createdAt descending
118
+ intentions.sort((a, b) => {
119
+ const salienceDiff = salienceRank(b.salience) - salienceRank(a.salience);
120
+ if (salienceDiff !== 0)
121
+ return salienceDiff;
122
+ return b.createdAt.localeCompare(a.createdAt);
123
+ });
124
+ const result = intentions.slice(0, limit);
125
+ (0, runtime_1.emitNervesEvent)({
126
+ component: "heart",
127
+ event: "heart.intentions_read",
128
+ message: `read ${result.length} open intentions`,
129
+ meta: { count: result.length, total: intentions.length, limit },
130
+ });
131
+ return result;
132
+ }
133
+ function readIntentionFile(agentRoot, id) {
134
+ const filePath = intentionFilePath(agentRoot, id);
135
+ if (!fs.existsSync(filePath)) {
136
+ throw new Error(`Intention not found: ${id}`);
137
+ }
138
+ return JSON.parse(fs.readFileSync(filePath, "utf-8"));
139
+ }
140
+ function writeIntentionFile(agentRoot, intention) {
141
+ fs.writeFileSync(intentionFilePath(agentRoot, intention.id), JSON.stringify(intention, null, 2), "utf-8");
142
+ }
143
+ function resolveIntention(agentRoot, id) {
144
+ const intention = readIntentionFile(agentRoot, id);
145
+ intention.status = "done";
146
+ intention.updatedAt = new Date().toISOString();
147
+ writeIntentionFile(agentRoot, intention);
148
+ (0, runtime_1.emitNervesEvent)({
149
+ component: "heart",
150
+ event: "heart.intention_resolved",
151
+ message: `intention resolved: ${intention.content.slice(0, 60)}`,
152
+ meta: { intentionId: id },
153
+ });
154
+ return intention;
155
+ }
156
+ function dismissIntention(agentRoot, id) {
157
+ const intention = readIntentionFile(agentRoot, id);
158
+ intention.status = "dismissed";
159
+ intention.updatedAt = new Date().toISOString();
160
+ writeIntentionFile(agentRoot, intention);
161
+ (0, runtime_1.emitNervesEvent)({
162
+ component: "heart",
163
+ event: "heart.intention_dismissed",
164
+ message: `intention dismissed: ${intention.content.slice(0, 60)}`,
165
+ meta: { intentionId: id },
166
+ });
167
+ return intention;
168
+ }
@@ -41,6 +41,7 @@ exports.readPendingObligations = readPendingObligations;
41
41
  exports.advanceObligation = advanceObligation;
42
42
  exports.fulfillObligation = fulfillObligation;
43
43
  exports.findPendingObligationForOrigin = findPendingObligationForOrigin;
44
+ exports.enrichObligation = enrichObligation;
44
45
  const fs = __importStar(require("fs"));
45
46
  const path = __importStar(require("path"));
46
47
  const runtime_1 = require("../nerves/runtime");
@@ -195,3 +196,25 @@ function findPendingObligationForOrigin(agentRoot, origin) {
195
196
  && ob.origin.channel === origin.channel
196
197
  && ob.origin.key === origin.key);
197
198
  }
199
+ function enrichObligation(agentRoot, id, meaning) {
200
+ const filePath = obligationFilePath(agentRoot, id);
201
+ if (!fs.existsSync(filePath)) {
202
+ throw new Error(`Obligation not found: ${id}`);
203
+ }
204
+ const raw = fs.readFileSync(filePath, "utf-8");
205
+ const obligation = JSON.parse(raw);
206
+ obligation.meaning = meaning;
207
+ obligation.updatedAt = new Date().toISOString();
208
+ fs.writeFileSync(filePath, JSON.stringify(obligation, null, 2), "utf-8");
209
+ (0, runtime_1.emitNervesEvent)({
210
+ component: "engine",
211
+ event: "engine.obligation_enriched",
212
+ message: "obligation enriched with meaning",
213
+ meta: {
214
+ obligationId: id,
215
+ salience: meaning.salience,
216
+ stalenessClass: meaning.stalenessClass,
217
+ },
218
+ });
219
+ return obligation;
220
+ }