@ouro.bot/cli 0.1.0-alpha.724 → 0.1.0-alpha.725
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 +12 -0
- package/dist/heart/active-work.js +10 -3
- package/dist/heart/core.js +343 -77
- package/dist/heart/daemon/cli-exec.js +72 -14
- package/dist/heart/daemon/cli-help.js +13 -2
- package/dist/heart/daemon/cli-parse.js +82 -1
- package/dist/heart/daemon/daemon.js +286 -33
- package/dist/heart/daemon/doctor.js +21 -6
- package/dist/heart/daemon/habit-private-wake.js +6 -1
- package/dist/heart/habits/habit-cancel.js +810 -0
- package/dist/heart/habits/habit-lifecycle.js +1327 -0
- package/dist/heart/habits/habit-migration.js +28 -23
- package/dist/heart/habits/habit-parser.js +72 -8
- package/dist/heart/habits/habit-runtime-state.js +3 -24
- package/dist/heart/habits/habit-scheduler.js +268 -50
- package/dist/heart/habits/habit-session.js +16 -0
- package/dist/heart/hatch/hatch-flow.js +6 -4
- package/dist/heart/mailbox/readers/runtime-readers.js +26 -27
- package/dist/heart/orientation-frame.js +58 -1
- package/dist/heart/provider-attempt.js +4 -1
- package/dist/heart/providers/anthropic.js +23 -2
- package/dist/heart/start-of-turn-packet.js +14 -11
- package/dist/heart/streaming.js +565 -185
- package/dist/mind/obligation-steering.js +15 -9
- package/dist/mind/prompt.js +58 -26
- package/dist/nerves/coverage/run-artifacts.js +55 -35
- package/dist/nerves/review/cli.js +2 -2
- package/dist/nerves/review/core.js +14 -7
- package/dist/repertoire/tools-base.js +2 -0
- package/dist/repertoire/tools-habits.js +103 -0
- package/dist/repertoire/tools.js +18 -3
- package/dist/rsvp/cli.js +126 -20
- package/dist/rsvp/diagnostics.js +12 -2
- package/dist/rsvp/habit-policy.js +7 -0
- package/dist/rsvp/habit-stage.js +19 -4
- package/dist/rsvp/native-habit-runner.js +151 -11
- package/dist/rsvp/outbound-state.js +360 -0
- package/dist/senses/bluebubbles/client.js +90 -17
- package/dist/senses/bluebubbles/inbound-log.js +1 -0
- package/dist/senses/bluebubbles/index.js +662 -425
- package/dist/senses/bluebubbles/model.js +57 -13
- package/dist/senses/bluebubbles/mutation-log.js +21 -10
- package/dist/senses/bluebubbles/reaction-policy.js +55 -0
- package/dist/senses/bluebubbles/semantic-receipts.js +1818 -0
- package/dist/senses/cli/tui-store.js +1 -0
- package/dist/senses/cli.js +1 -0
- package/dist/senses/habit-lifecycle-guard.js +24 -0
- package/dist/senses/ingress-evidence.js +2 -0
- package/dist/senses/pipeline.js +90 -24
- package/dist/senses/private-runtime-worker.js +21 -20
- package/dist/senses/private-runtime.js +79 -29
- package/dist/senses/shared-turn.js +1 -0
- package/dist/senses/teams.js +1 -0
- package/package.json +6 -1
|
@@ -92,9 +92,11 @@ function buildChatRef(data, threadOriginatorGuid) {
|
|
|
92
92
|
}
|
|
93
93
|
function extractSender(data, chat) {
|
|
94
94
|
const handle = asRecord(data.handle) ?? asRecord(data.sender) ?? null;
|
|
95
|
-
const
|
|
95
|
+
const observedRawId = readString(handle, "address") ??
|
|
96
96
|
readString(handle, "id") ??
|
|
97
|
-
readString(data, "senderId")
|
|
97
|
+
readString(data, "senderId");
|
|
98
|
+
const observed = typeof observedRawId === "string" && observedRawId.trim().length > 0;
|
|
99
|
+
const rawId = observedRawId ??
|
|
98
100
|
chat.chatIdentifier ??
|
|
99
101
|
chat.chatGuid ??
|
|
100
102
|
"unknown";
|
|
@@ -105,6 +107,7 @@ function extractSender(data, chat) {
|
|
|
105
107
|
externalId,
|
|
106
108
|
rawId,
|
|
107
109
|
displayName,
|
|
110
|
+
observed,
|
|
108
111
|
};
|
|
109
112
|
}
|
|
110
113
|
function extractAttachments(data) {
|
|
@@ -163,7 +166,7 @@ function normalizeReactionName(value) {
|
|
|
163
166
|
return trimmed ? trimmed.toLowerCase() : undefined;
|
|
164
167
|
}
|
|
165
168
|
/**
|
|
166
|
-
* iMessage tapbacks: associated_message_type 2000-
|
|
169
|
+
* iMessage tapbacks: associated_message_type 2000-2006 add a tapback, 3000-3006
|
|
167
170
|
* remove the same tapback. BlueBubbles may send either the code or the name.
|
|
168
171
|
*/
|
|
169
172
|
const REACTION_VOCABULARY = [
|
|
@@ -173,17 +176,26 @@ const REACTION_VOCABULARY = [
|
|
|
173
176
|
{ code: 2003, name: "laugh", verb: "laughed at", noun: "laugh" },
|
|
174
177
|
{ code: 2004, name: "emphasize", verb: "emphasized", noun: "emphasis" },
|
|
175
178
|
{ code: 2005, name: "question", verb: "questioned", noun: "question" },
|
|
179
|
+
{ code: 2006, name: "custom", verb: "reacted with custom emoji to", noun: "custom emoji" },
|
|
176
180
|
];
|
|
177
181
|
const REACTION_EXCERPT_MAX_LENGTH = 80;
|
|
178
|
-
function describeBlueBubblesReaction(raw) {
|
|
182
|
+
function describeBlueBubblesReaction(raw, rawTransportValue = raw) {
|
|
179
183
|
const stripped = raw.startsWith("-") ? raw.slice(1) : raw;
|
|
180
184
|
const code = /^\d+$/.test(stripped) ? Number(stripped) : undefined;
|
|
181
185
|
const removal = raw.startsWith("-") || (code !== undefined && code >= 3000 && code < 4000);
|
|
182
186
|
const action = removal ? "remove" : "add";
|
|
183
187
|
const entry = REACTION_VOCABULARY.find((candidate) => candidate.name === stripped || candidate.code === code || candidate.code + 1000 === code);
|
|
188
|
+
const canonicalValue = entry?.name ?? "unknown";
|
|
184
189
|
if (!entry)
|
|
185
|
-
return { raw, action };
|
|
186
|
-
return {
|
|
190
|
+
return { raw, rawTransportValue, canonicalValue, action };
|
|
191
|
+
return {
|
|
192
|
+
raw,
|
|
193
|
+
rawTransportValue,
|
|
194
|
+
canonicalValue,
|
|
195
|
+
action,
|
|
196
|
+
verb: entry.verb,
|
|
197
|
+
noun: entry.noun,
|
|
198
|
+
};
|
|
187
199
|
}
|
|
188
200
|
function reactionExcerpt(text) {
|
|
189
201
|
return text.length > REACTION_EXCERPT_MAX_LENGTH
|
|
@@ -243,17 +255,35 @@ function detectMutationType(eventType, data, reactionName) {
|
|
|
243
255
|
if (reactionName)
|
|
244
256
|
return "reaction";
|
|
245
257
|
if (eventType === "updated-message") {
|
|
246
|
-
if (readNumber(data, "dateRetracted"))
|
|
258
|
+
if (readNumber(data, "dateRetracted") !== undefined)
|
|
247
259
|
return "unsend";
|
|
248
|
-
if (readNumber(data, "dateEdited"))
|
|
260
|
+
if (readNumber(data, "dateEdited") !== undefined)
|
|
249
261
|
return "edit";
|
|
250
|
-
if (readNumber(data, "dateRead"))
|
|
262
|
+
if (readNumber(data, "dateRead") !== undefined)
|
|
251
263
|
return "read";
|
|
252
|
-
if (readBoolean(data, "isDelivered") || readNumber(data, "dateDelivered"))
|
|
264
|
+
if (readBoolean(data, "isDelivered") || readNumber(data, "dateDelivered") !== undefined)
|
|
253
265
|
return "delivery";
|
|
254
266
|
}
|
|
255
267
|
return null;
|
|
256
268
|
}
|
|
269
|
+
function readProviderRevision(data) {
|
|
270
|
+
const value = data.revision;
|
|
271
|
+
if (typeof value !== "string" && typeof value !== "number")
|
|
272
|
+
return undefined;
|
|
273
|
+
const normalized = String(value).trim();
|
|
274
|
+
return normalized || undefined;
|
|
275
|
+
}
|
|
276
|
+
function mutationEffectiveTimestamp(mutationType, data) {
|
|
277
|
+
if (mutationType === "reaction")
|
|
278
|
+
return readNumber(data, "dateCreated");
|
|
279
|
+
if (mutationType === "edit")
|
|
280
|
+
return readNumber(data, "dateEdited");
|
|
281
|
+
if (mutationType === "unsend")
|
|
282
|
+
return readNumber(data, "dateRetracted");
|
|
283
|
+
if (mutationType === "read")
|
|
284
|
+
return readNumber(data, "dateRead");
|
|
285
|
+
return readNumber(data, "dateDelivered");
|
|
286
|
+
}
|
|
257
287
|
function normalizeBlueBubblesEvent(payload) {
|
|
258
288
|
const envelope = asRecord(payload);
|
|
259
289
|
const eventType = readString(envelope, "type")?.trim() ?? "";
|
|
@@ -286,14 +316,24 @@ function normalizeBlueBubblesEvent(payload) {
|
|
|
286
316
|
const chat = buildChatRef(data, threadOriginatorGuid);
|
|
287
317
|
const sender = extractSender(data, chat);
|
|
288
318
|
const timestamp = readNumber(data, "dateCreated") ?? Date.now();
|
|
289
|
-
const fromMe = readBoolean(data, "isFromMe") ??
|
|
319
|
+
const fromMe = readBoolean(data, "isFromMe") ?? null;
|
|
290
320
|
const attachments = extractAttachments(data);
|
|
291
321
|
const reactionName = normalizeReactionName(data.associatedMessageType);
|
|
292
|
-
const reaction = reactionName
|
|
322
|
+
const reaction = reactionName
|
|
323
|
+
? describeBlueBubblesReaction(reactionName, String(data.associatedMessageType))
|
|
324
|
+
: undefined;
|
|
293
325
|
const targetMessageGuid = reaction
|
|
294
326
|
? stripPartPrefix(readString(data, "associatedMessageGuid"))
|
|
295
327
|
: undefined;
|
|
296
328
|
const mutationType = detectMutationType(eventType, data, reactionName);
|
|
329
|
+
const revision = mutationType ? readProviderRevision(data) : undefined;
|
|
330
|
+
const effectiveTimestamp = mutationType
|
|
331
|
+
? mutationEffectiveTimestamp(mutationType, data)
|
|
332
|
+
: undefined;
|
|
333
|
+
const editedText = mutationType === "edit" ? readString(data, "text") : undefined;
|
|
334
|
+
const retractionTimestamp = mutationType === "unsend"
|
|
335
|
+
? readNumber(data, "dateRetracted")
|
|
336
|
+
: undefined;
|
|
297
337
|
const requiresRepair = (readBoolean(data, "hasPayloadData") ?? false) ||
|
|
298
338
|
attachments.length > 0 ||
|
|
299
339
|
eventType === "updated-message";
|
|
@@ -314,6 +354,10 @@ function normalizeBlueBubblesEvent(payload) {
|
|
|
314
354
|
: buildMutationText(mutationType, data),
|
|
315
355
|
requiresRepair,
|
|
316
356
|
...(reaction ? { reaction } : {}),
|
|
357
|
+
...(editedText !== undefined ? { editedText } : {}),
|
|
358
|
+
...(revision ? { revision } : {}),
|
|
359
|
+
...(effectiveTimestamp !== undefined ? { effectiveTimestamp } : {}),
|
|
360
|
+
...(retractionTimestamp !== undefined ? { retractionTimestamp } : {}),
|
|
317
361
|
}
|
|
318
362
|
: {
|
|
319
363
|
kind: "message",
|
|
@@ -323,7 +367,7 @@ function normalizeBlueBubblesEvent(payload) {
|
|
|
323
367
|
fromMe,
|
|
324
368
|
sender,
|
|
325
369
|
chat,
|
|
326
|
-
text: readString(data, "text")
|
|
370
|
+
text: readString(data, "text") ?? "",
|
|
327
371
|
textForAgent: formatMessageText(data, attachments),
|
|
328
372
|
attachments,
|
|
329
373
|
balloonBundleId: readString(data, "balloonBundleId")?.trim() || undefined,
|
|
@@ -35,6 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.getBlueBubblesMutationLogPath = getBlueBubblesMutationLogPath;
|
|
37
37
|
exports.recordBlueBubblesMutation = recordBlueBubblesMutation;
|
|
38
|
+
exports.listRecordedBlueBubblesMutations = listRecordedBlueBubblesMutations;
|
|
38
39
|
exports.listBlueBubblesRecoveryCandidates = listBlueBubblesRecoveryCandidates;
|
|
39
40
|
const fs = __importStar(require("node:fs"));
|
|
40
41
|
const path = __importStar(require("node:path"));
|
|
@@ -73,7 +74,7 @@ function recordBlueBubblesMutation(agentName, event) {
|
|
|
73
74
|
});
|
|
74
75
|
return filePath;
|
|
75
76
|
}
|
|
76
|
-
function
|
|
77
|
+
function readBlueBubblesMutationRows(agentName) {
|
|
77
78
|
const rootDir = path.join((0, identity_1.getAgentRoot)(agentName), "state", "senses", "bluebubbles", "mutations");
|
|
78
79
|
let files;
|
|
79
80
|
try {
|
|
@@ -82,7 +83,7 @@ function listBlueBubblesRecoveryCandidates(agentName) {
|
|
|
82
83
|
catch {
|
|
83
84
|
return [];
|
|
84
85
|
}
|
|
85
|
-
const
|
|
86
|
+
const entries = [];
|
|
86
87
|
for (const file of files.filter((entry) => entry.endsWith(".ndjson")).sort()) {
|
|
87
88
|
const filePath = path.join(rootDir, file);
|
|
88
89
|
let raw = "";
|
|
@@ -98,19 +99,29 @@ function listBlueBubblesRecoveryCandidates(agentName) {
|
|
|
98
99
|
continue;
|
|
99
100
|
try {
|
|
100
101
|
const entry = JSON.parse(trimmed);
|
|
101
|
-
if (typeof entry.messageGuid !== "string"
|
|
102
|
-
|| !entry.messageGuid.trim()
|
|
103
|
-
|| entry.fromMe
|
|
104
|
-
|| entry.shouldNotifyAgent
|
|
105
|
-
|| (entry.mutationType !== "read" && entry.mutationType !== "delivery")) {
|
|
102
|
+
if (typeof entry.messageGuid !== "string" || !entry.messageGuid.trim())
|
|
106
103
|
continue;
|
|
107
|
-
|
|
108
|
-
deduped.set(entry.messageGuid, entry);
|
|
104
|
+
entries.push(entry);
|
|
109
105
|
}
|
|
110
106
|
catch {
|
|
111
|
-
//
|
|
107
|
+
// Keep malformed legacy rows inert while retaining readable audit rows.
|
|
112
108
|
}
|
|
113
109
|
}
|
|
114
110
|
}
|
|
111
|
+
return entries;
|
|
112
|
+
}
|
|
113
|
+
function listRecordedBlueBubblesMutations(agentName) {
|
|
114
|
+
return readBlueBubblesMutationRows(agentName).filter((entry) => (typeof entry.sessionKey === "string" && entry.sessionKey.trim().length > 0));
|
|
115
|
+
}
|
|
116
|
+
function listBlueBubblesRecoveryCandidates(agentName) {
|
|
117
|
+
const deduped = new Map();
|
|
118
|
+
for (const entry of readBlueBubblesMutationRows(agentName)) {
|
|
119
|
+
if (entry.fromMe !== false
|
|
120
|
+
|| entry.shouldNotifyAgent
|
|
121
|
+
|| (entry.mutationType !== "read" && entry.mutationType !== "delivery")) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
deduped.set(entry.messageGuid, entry);
|
|
125
|
+
}
|
|
115
126
|
return [...deduped.values()].sort((left, right) => left.recordedAt.localeCompare(right.recordedAt));
|
|
116
127
|
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.classifyBlueBubblesReaction = classifyBlueBubblesReaction;
|
|
4
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
5
|
+
const POSITIVE_REACTIONS = new Set([
|
|
6
|
+
"love",
|
|
7
|
+
"like",
|
|
8
|
+
"laugh",
|
|
9
|
+
"emphasize",
|
|
10
|
+
]);
|
|
11
|
+
function classifyBlueBubblesReaction(input) {
|
|
12
|
+
let decision;
|
|
13
|
+
if (input.fromMe) {
|
|
14
|
+
decision = { route: "capture_only", outcome: "ignored_self" };
|
|
15
|
+
}
|
|
16
|
+
else if (input.action === "remove") {
|
|
17
|
+
decision = { route: "capture_only", outcome: "capture_only_removal" };
|
|
18
|
+
}
|
|
19
|
+
else if (POSITIVE_REACTIONS.has(input.canonicalValue)) {
|
|
20
|
+
decision = { route: "capture_only", outcome: "capture_only_positive" };
|
|
21
|
+
}
|
|
22
|
+
else if (input.canonicalValue === "custom") {
|
|
23
|
+
decision = { route: "capture_only", outcome: "capture_only_custom" };
|
|
24
|
+
}
|
|
25
|
+
else if (input.canonicalValue === "unknown") {
|
|
26
|
+
decision = { route: "capture_only", outcome: "capture_only_unknown" };
|
|
27
|
+
}
|
|
28
|
+
else if (input.targetAuthorship !== "agent") {
|
|
29
|
+
decision = { route: "capture_only", outcome: "capture_only_target_not_agent" };
|
|
30
|
+
}
|
|
31
|
+
else if (input.trustedActor === undefined) {
|
|
32
|
+
decision = { route: "trust_required" };
|
|
33
|
+
}
|
|
34
|
+
else if (!input.trustedActor) {
|
|
35
|
+
decision = { route: "capture_only", outcome: "capture_only_untrusted_actor" };
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
decision = { route: "restricted_feedback" };
|
|
39
|
+
}
|
|
40
|
+
(0, runtime_1.emitNervesEvent)({
|
|
41
|
+
component: "senses",
|
|
42
|
+
event: "senses.bluebubbles_reaction_policy_evaluated",
|
|
43
|
+
message: "evaluated bluebubbles reaction routing policy",
|
|
44
|
+
meta: {
|
|
45
|
+
action: input.action,
|
|
46
|
+
canonicalValue: input.canonicalValue,
|
|
47
|
+
fromMe: input.fromMe,
|
|
48
|
+
targetAuthorship: input.targetAuthorship,
|
|
49
|
+
trustEvaluated: input.trustedActor !== undefined,
|
|
50
|
+
route: decision.route,
|
|
51
|
+
outcome: decision.route === "capture_only" ? decision.outcome : null,
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
return decision;
|
|
55
|
+
}
|