@ouro.bot/cli 0.1.0-alpha.705 → 0.1.0-alpha.706
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,12 @@
|
|
|
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.706",
|
|
6
|
+
"changes": [
|
|
7
|
+
"Route native RSVP habit checks through typed refresh execution instead of private-runtime wake policy."
|
|
8
|
+
]
|
|
9
|
+
},
|
|
4
10
|
{
|
|
5
11
|
"version": "0.1.0-alpha.705",
|
|
6
12
|
"changes": [
|
|
@@ -63,6 +63,7 @@ const pulse_1 = require("./pulse");
|
|
|
63
63
|
const socket_client_1 = require("./socket-client");
|
|
64
64
|
const await_private_wake_1 = require("./await-private-wake");
|
|
65
65
|
const habit_private_wake_1 = require("./habit-private-wake");
|
|
66
|
+
const habit_policy_1 = require("../../rsvp/habit-policy");
|
|
66
67
|
const bundle_manifest_1 = require("../../mind/bundle-manifest");
|
|
67
68
|
const mcp_canary_1 = require("./mcp-canary");
|
|
68
69
|
const context_loss_sentinel_1 = require("../context-loss-sentinel");
|
|
@@ -629,6 +630,25 @@ void daemon.start().then(async () => {
|
|
|
629
630
|
habitsDir,
|
|
630
631
|
osCronManager,
|
|
631
632
|
onHabitFire: (habitName, trigger, context) => {
|
|
633
|
+
if ((0, habit_policy_1.isRsvpHabitName)(habitName)) {
|
|
634
|
+
(0, socket_client_1.sendDaemonCommand)(socketPath, {
|
|
635
|
+
kind: "habit.poke",
|
|
636
|
+
agent,
|
|
637
|
+
habitName,
|
|
638
|
+
trigger,
|
|
639
|
+
...(context?.occurrenceId ? { occurrenceId: context.occurrenceId } : {}),
|
|
640
|
+
}).catch((error) => {
|
|
641
|
+
emitHabitPrivateWakeDispatchError({
|
|
642
|
+
agent,
|
|
643
|
+
habitName,
|
|
644
|
+
trigger,
|
|
645
|
+
triggerSource: `habit-${trigger}`,
|
|
646
|
+
socketPath,
|
|
647
|
+
error,
|
|
648
|
+
});
|
|
649
|
+
});
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
632
652
|
const command = (0, habit_private_wake_1.buildHabitPrivateWakeCommand)({
|
|
633
653
|
agent,
|
|
634
654
|
habitName,
|
|
@@ -567,6 +567,7 @@ class OuroDaemon {
|
|
|
567
567
|
privateRuntimePolicyDeps;
|
|
568
568
|
onStopCommandComplete;
|
|
569
569
|
externalEventRoot;
|
|
570
|
+
rsvpHabitRunner;
|
|
570
571
|
constructor(options) {
|
|
571
572
|
this.socketPath = options.socketPath;
|
|
572
573
|
this.processManager = options.processManager;
|
|
@@ -580,6 +581,7 @@ class OuroDaemon {
|
|
|
580
581
|
this.privateRuntimePolicyDeps = options.privateRuntimePolicyDeps ?? {};
|
|
581
582
|
this.onStopCommandComplete = options.onStopCommandComplete ?? null;
|
|
582
583
|
this.externalEventRoot = options.externalEventRoot ?? null;
|
|
584
|
+
this.rsvpHabitRunner = options.rsvpHabitRunner;
|
|
583
585
|
}
|
|
584
586
|
/* v8 ignore start -- default mailbox server wiring: production-only path, tests inject mailboxServerFactory stub instead. startMailboxHttpServer itself has full coverage in mailbox-http.test.ts @preserve */
|
|
585
587
|
createDefaultMailboxServer() {
|
|
@@ -1226,6 +1228,8 @@ class OuroDaemon {
|
|
|
1226
1228
|
}
|
|
1227
1229
|
if (trigger === "poke" || trigger === "manual")
|
|
1228
1230
|
return undefined;
|
|
1231
|
+
if (typeof command.occurrenceId === "string" && command.occurrenceId.trim().length > 0)
|
|
1232
|
+
return command.occurrenceId.trim();
|
|
1229
1233
|
if (!fs.existsSync(habitPath))
|
|
1230
1234
|
return { skipReason: "habit file not found" };
|
|
1231
1235
|
const habit = parsedHabit ?? (0, habit_runtime_state_1.applyHabitRuntimeState)(agentRoot, (0, habit_parser_1.parseHabitFile)(fs.readFileSync(habitPath, "utf-8"), habitPath));
|
|
@@ -1236,6 +1240,24 @@ class OuroDaemon {
|
|
|
1236
1240
|
return `${trigger}:first-run:${cadence}`;
|
|
1237
1241
|
return `${trigger}:last-run:${habit.lastRun}:cadence:${cadence}`;
|
|
1238
1242
|
}
|
|
1243
|
+
async runNativeRsvpHabit(command, trigger, occurrenceId) {
|
|
1244
|
+
const runner = this.rsvpHabitRunner ?? (async (input) => {
|
|
1245
|
+
const { runNativeRsvpHabit } = await Promise.resolve().then(() => __importStar(require("../../rsvp/native-habit-runner")));
|
|
1246
|
+
return runNativeRsvpHabit(input);
|
|
1247
|
+
});
|
|
1248
|
+
const result = await runner({
|
|
1249
|
+
agent: command.agent,
|
|
1250
|
+
bundlesRoot: this.bundlesRoot,
|
|
1251
|
+
habitName: command.habitName,
|
|
1252
|
+
trigger,
|
|
1253
|
+
...(occurrenceId ? { occurrenceId } : {}),
|
|
1254
|
+
});
|
|
1255
|
+
return {
|
|
1256
|
+
ok: result.ok,
|
|
1257
|
+
message: result.message,
|
|
1258
|
+
data: result,
|
|
1259
|
+
};
|
|
1260
|
+
}
|
|
1239
1261
|
buildPrivateRuntimeWorkerWakeMessage(command, decision) {
|
|
1240
1262
|
const awaitName = (0, await_private_wake_1.awaitNameFromPrivateWakeCommand)(command);
|
|
1241
1263
|
if (awaitName) {
|
|
@@ -1635,7 +1657,7 @@ class OuroDaemon {
|
|
|
1635
1657
|
if (!(0, flight_recorder_1.isHabitRunTrigger)(trigger)) {
|
|
1636
1658
|
return { ok: false, error: `invalid habit trigger: ${String(trigger)}` };
|
|
1637
1659
|
}
|
|
1638
|
-
if (!this.hasManagedPrivateRuntime(command.agent)) {
|
|
1660
|
+
if (!(0, habit_policy_1.isRsvpHabitName)(command.habitName) && !this.hasManagedPrivateRuntime(command.agent)) {
|
|
1639
1661
|
return {
|
|
1640
1662
|
ok: false,
|
|
1641
1663
|
error: `No managed agent '${command.agent}' is registered with daemon-managed private runtime.`,
|
|
@@ -1648,6 +1670,9 @@ class OuroDaemon {
|
|
|
1648
1670
|
message: `skipped scheduled habit ${command.habitName} for ${command.agent}: ${occurrenceId.skipReason}`,
|
|
1649
1671
|
};
|
|
1650
1672
|
}
|
|
1673
|
+
if ((0, habit_policy_1.isRsvpHabitName)(command.habitName)) {
|
|
1674
|
+
return this.runNativeRsvpHabit(command, trigger, occurrenceId);
|
|
1675
|
+
}
|
|
1651
1676
|
return this.handlePrivateRuntimeWake((0, habit_private_wake_1.buildHabitPrivateWakeCommand)({
|
|
1652
1677
|
agent: command.agent,
|
|
1653
1678
|
habitName: command.habitName,
|
|
@@ -0,0 +1,321 @@
|
|
|
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.runNativeRsvpHabit = runNativeRsvpHabit;
|
|
37
|
+
const fs = __importStar(require("node:fs"));
|
|
38
|
+
const path = __importStar(require("node:path"));
|
|
39
|
+
const node_crypto_1 = require("node:crypto");
|
|
40
|
+
const habit_parser_1 = require("../heart/habits/habit-parser");
|
|
41
|
+
const habit_runtime_state_1 = require("../heart/habits/habit-runtime-state");
|
|
42
|
+
const habit_session_1 = require("../heart/habits/habit-session");
|
|
43
|
+
const run_ledger_1 = require("../heart/run-ledger");
|
|
44
|
+
const spend_ledger_1 = require("./spend-ledger");
|
|
45
|
+
const habit_policy_1 = require("./habit-policy");
|
|
46
|
+
const runtime_1 = require("../nerves/runtime");
|
|
47
|
+
function sha256Hex(input) {
|
|
48
|
+
return (0, node_crypto_1.createHash)("sha256").update(input).digest("hex");
|
|
49
|
+
}
|
|
50
|
+
function nowIso(now) {
|
|
51
|
+
const value = now ? now() : new Date();
|
|
52
|
+
return value instanceof Date ? value.toISOString() : value;
|
|
53
|
+
}
|
|
54
|
+
function nativeRunId(input) {
|
|
55
|
+
const digest = sha256Hex(JSON.stringify({
|
|
56
|
+
agent: input.agent,
|
|
57
|
+
habitName: input.habitName,
|
|
58
|
+
trigger: input.trigger,
|
|
59
|
+
occurrenceId: input.occurrenceId ?? null,
|
|
60
|
+
})).slice(0, 24);
|
|
61
|
+
return `rsvp-${input.trigger}-${digest}`;
|
|
62
|
+
}
|
|
63
|
+
function noopCliDeps(input, agentRoot) {
|
|
64
|
+
return {
|
|
65
|
+
socketPath: "",
|
|
66
|
+
sendCommand: async () => ({ ok: false, error: "daemon socket unavailable in native RSVP habit runner" }),
|
|
67
|
+
startDaemonProcess: async () => ({ pid: null }),
|
|
68
|
+
writeStdout: () => undefined,
|
|
69
|
+
checkSocketAlive: async () => false,
|
|
70
|
+
cleanupStaleSocket: () => undefined,
|
|
71
|
+
fallbackPendingMessage: () => "daemon socket unavailable in native RSVP habit runner",
|
|
72
|
+
bundlesRoot: input.bundlesRoot,
|
|
73
|
+
agentBundleRoot: agentRoot,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
async function defaultRunRefresh(command, deps) {
|
|
77
|
+
const { runRsvpCliCommand } = await Promise.resolve().then(() => __importStar(require("./cli")));
|
|
78
|
+
return runRsvpCliCommand(command, deps);
|
|
79
|
+
}
|
|
80
|
+
function parseRefreshPayload(text) {
|
|
81
|
+
const parsed = JSON.parse(text);
|
|
82
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
83
|
+
throw new Error("RSVP refresh returned a non-object payload");
|
|
84
|
+
}
|
|
85
|
+
return parsed;
|
|
86
|
+
}
|
|
87
|
+
function refreshCommandFor(input, sendAllowed, mode) {
|
|
88
|
+
return {
|
|
89
|
+
kind: "rsvp.refresh",
|
|
90
|
+
agent: input.agent,
|
|
91
|
+
mode,
|
|
92
|
+
json: true,
|
|
93
|
+
...(sendAllowed ? { allowSend: true } : { noSend: true }),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function permissionEnvelope(sendAllowed) {
|
|
97
|
+
return {
|
|
98
|
+
schemaVersion: 1,
|
|
99
|
+
canMessageOutward: sendAllowed,
|
|
100
|
+
returnRoutes: sendAllowed
|
|
101
|
+
? [{ kind: "family", recipient: "family", status: "allowed" }]
|
|
102
|
+
: [],
|
|
103
|
+
deniedTools: sendAllowed ? [] : ["send_message", "surface"],
|
|
104
|
+
warnings: [],
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
function toolPolicy(sendAllowed) {
|
|
108
|
+
return {
|
|
109
|
+
requestedTools: [...habit_policy_1.RSVP_HABIT_ALLOWED_TOOLS],
|
|
110
|
+
grantedTools: [...habit_policy_1.RSVP_HABIT_ALLOWED_TOOLS],
|
|
111
|
+
deniedTools: [],
|
|
112
|
+
outwardMessagingAllowed: sendAllowed,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
function stringField(record, key) {
|
|
116
|
+
const value = record[key];
|
|
117
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
|
118
|
+
}
|
|
119
|
+
function refreshRecord(payload) {
|
|
120
|
+
const value = payload.refresh;
|
|
121
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
122
|
+
}
|
|
123
|
+
function producedRefsFor(payload) {
|
|
124
|
+
if (payload.sendAllowed === true)
|
|
125
|
+
return [];
|
|
126
|
+
const snapshotId = stringField(refreshRecord(payload) ?? {}, "snapshotId");
|
|
127
|
+
return snapshotId ? [{ kind: "none", locator: `state/rsvp/snapshots/${snapshotId}.json` }] : [];
|
|
128
|
+
}
|
|
129
|
+
function surfaceAttemptsFor(payload, requestedSend, errorMessage) {
|
|
130
|
+
if (payload.sendAllowed === true) {
|
|
131
|
+
return [{
|
|
132
|
+
recipient: "rsvp",
|
|
133
|
+
channel: "bluebubbles",
|
|
134
|
+
reason: "status",
|
|
135
|
+
result: "sent",
|
|
136
|
+
}];
|
|
137
|
+
}
|
|
138
|
+
if (requestedSend && errorMessage) {
|
|
139
|
+
return [{
|
|
140
|
+
recipient: "rsvp",
|
|
141
|
+
channel: "bluebubbles",
|
|
142
|
+
reason: "blocked",
|
|
143
|
+
result: "blocked",
|
|
144
|
+
error: errorMessage,
|
|
145
|
+
}];
|
|
146
|
+
}
|
|
147
|
+
return [];
|
|
148
|
+
}
|
|
149
|
+
function payloadError(payload) {
|
|
150
|
+
if (payload.ok === false || typeof payload.requires === "string") {
|
|
151
|
+
return stringField(payload, "message") ?? "RSVP refresh did not complete";
|
|
152
|
+
}
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
function recordNativeRunLedger(input) {
|
|
156
|
+
const target = {
|
|
157
|
+
habitName: input.habitName,
|
|
158
|
+
runId: input.runId,
|
|
159
|
+
trigger: input.trigger,
|
|
160
|
+
occurrenceId: input.occurrenceId ?? null,
|
|
161
|
+
command: "rsvp.refresh",
|
|
162
|
+
};
|
|
163
|
+
const record = (0, run_ledger_1.createRunLedgerRecord)({
|
|
164
|
+
agent: input.agent,
|
|
165
|
+
triggerType: "habit",
|
|
166
|
+
sourceKind: "daemon",
|
|
167
|
+
senseOrHabit: input.habitName,
|
|
168
|
+
lifecycle: input.lifecycle,
|
|
169
|
+
startedAt: input.startedAt,
|
|
170
|
+
...(input.endedAt ? { endedAt: input.endedAt } : {}),
|
|
171
|
+
...(input.lifecycle === "completed" || input.lifecycle === "error"
|
|
172
|
+
? { usage: (0, run_ledger_1.usageMetadataFromUsageData)(undefined, "none") }
|
|
173
|
+
: {}),
|
|
174
|
+
target,
|
|
175
|
+
idempotencyScope: target,
|
|
176
|
+
sessionRef: {
|
|
177
|
+
channel: "rsvp",
|
|
178
|
+
keyHash: `sha256:${sha256Hex(input.runId)}`,
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
(0, run_ledger_1.appendRunLedgerRecordNonFatal)(input.agentRoot, record);
|
|
182
|
+
try {
|
|
183
|
+
(0, spend_ledger_1.recordRsvpSpendLedgerRun)(input.agentRoot, record);
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
(0, runtime_1.emitNervesEvent)({
|
|
187
|
+
level: "error",
|
|
188
|
+
component: "rsvp",
|
|
189
|
+
event: "rsvp.native_habit_spend_ledger_error",
|
|
190
|
+
message: "failed to record native RSVP habit spend ledger row",
|
|
191
|
+
meta: { runId: input.runId, lifecycle: input.lifecycle, error: String(error) },
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
async function runNativeRsvpHabit(input) {
|
|
196
|
+
const agentRoot = path.join(input.bundlesRoot, `${input.agent}.ouro`);
|
|
197
|
+
const habitPath = path.join(agentRoot, "habits", `${input.habitName}.md`);
|
|
198
|
+
const startedAt = nowIso(input.now);
|
|
199
|
+
const runId = nativeRunId(input);
|
|
200
|
+
(0, runtime_1.emitNervesEvent)({
|
|
201
|
+
component: "rsvp",
|
|
202
|
+
event: "rsvp.native_habit_start",
|
|
203
|
+
message: "native RSVP habit starting",
|
|
204
|
+
meta: {
|
|
205
|
+
agent: input.agent,
|
|
206
|
+
habitName: input.habitName,
|
|
207
|
+
trigger: input.trigger,
|
|
208
|
+
occurrenceId: input.occurrenceId ?? null,
|
|
209
|
+
runId,
|
|
210
|
+
},
|
|
211
|
+
});
|
|
212
|
+
const habit = (0, habit_runtime_state_1.applyHabitRuntimeState)(agentRoot, (0, habit_parser_1.parseHabitFile)(fs.readFileSync(habitPath, "utf-8"), habitPath));
|
|
213
|
+
if (!habit.rsvp)
|
|
214
|
+
throw new Error(`RSVP habit metadata is required before native execution: ${input.habitName}`);
|
|
215
|
+
const policy = (0, habit_policy_1.rsvpHabitRuntimePolicy)(habit.rsvp);
|
|
216
|
+
const command = refreshCommandFor(input, policy.sendAllowed, habit.rsvp.mode);
|
|
217
|
+
const deps = noopCliDeps(input, agentRoot);
|
|
218
|
+
recordNativeRunLedger({
|
|
219
|
+
agentRoot,
|
|
220
|
+
agent: input.agent,
|
|
221
|
+
habitName: input.habitName,
|
|
222
|
+
runId,
|
|
223
|
+
trigger: input.trigger,
|
|
224
|
+
occurrenceId: input.occurrenceId,
|
|
225
|
+
startedAt,
|
|
226
|
+
lifecycle: "started",
|
|
227
|
+
});
|
|
228
|
+
let payload;
|
|
229
|
+
let errorMessage = null;
|
|
230
|
+
try {
|
|
231
|
+
payload = parseRefreshPayload(await (input.runRefresh ?? defaultRunRefresh)(command, deps));
|
|
232
|
+
errorMessage = payloadError(payload);
|
|
233
|
+
}
|
|
234
|
+
catch (error) {
|
|
235
|
+
payload = {
|
|
236
|
+
ok: false,
|
|
237
|
+
command: "rsvp.refresh",
|
|
238
|
+
sideEffect: false,
|
|
239
|
+
agent: input.agent,
|
|
240
|
+
mode: habit.rsvp.mode,
|
|
241
|
+
message: error instanceof Error ? error.message : String(error),
|
|
242
|
+
};
|
|
243
|
+
errorMessage = stringField(payload, "message") ?? "RSVP refresh failed";
|
|
244
|
+
}
|
|
245
|
+
const endedAt = nowIso(input.now);
|
|
246
|
+
const lifecycle = errorMessage ? "error" : "completed";
|
|
247
|
+
const surfaceAttempts = surfaceAttemptsFor(payload, policy.sendAllowed, errorMessage);
|
|
248
|
+
const errors = errorMessage ? [errorMessage] : [];
|
|
249
|
+
recordNativeRunLedger({
|
|
250
|
+
agentRoot,
|
|
251
|
+
agent: input.agent,
|
|
252
|
+
habitName: input.habitName,
|
|
253
|
+
runId,
|
|
254
|
+
trigger: input.trigger,
|
|
255
|
+
occurrenceId: input.occurrenceId,
|
|
256
|
+
startedAt,
|
|
257
|
+
endedAt,
|
|
258
|
+
lifecycle,
|
|
259
|
+
});
|
|
260
|
+
const completion = (0, habit_session_1.completeHabitRun)({
|
|
261
|
+
agentRoot,
|
|
262
|
+
habit,
|
|
263
|
+
runId,
|
|
264
|
+
trigger: input.trigger,
|
|
265
|
+
startedAt,
|
|
266
|
+
endedAt,
|
|
267
|
+
operationId: `rsvp-native:${input.trigger}:${input.occurrenceId ?? runId}`,
|
|
268
|
+
permissionEnvelope: permissionEnvelope(policy.sendAllowed),
|
|
269
|
+
toolPolicy: toolPolicy(policy.sendAllowed),
|
|
270
|
+
producedRefs: producedRefsFor(payload),
|
|
271
|
+
surfaceAttempts,
|
|
272
|
+
errors,
|
|
273
|
+
summarySnapshot: {
|
|
274
|
+
summary: errorMessage
|
|
275
|
+
? `Native RSVP habit failed: ${errorMessage}`
|
|
276
|
+
: "Native RSVP habit completed.",
|
|
277
|
+
decisions: [
|
|
278
|
+
`mode=${habit.rsvp.mode}`,
|
|
279
|
+
`sendAllowed=${String(policy.sendAllowed)}`,
|
|
280
|
+
],
|
|
281
|
+
nextLikelyStep: null,
|
|
282
|
+
},
|
|
283
|
+
});
|
|
284
|
+
const ok = lifecycle === "completed" && completion.receiptWritten && completion.runtimeStateRecorded;
|
|
285
|
+
const message = ok
|
|
286
|
+
? `native RSVP habit ${input.habitName} completed for ${input.agent}`
|
|
287
|
+
: `native RSVP habit ${input.habitName} failed for ${input.agent}: ${errorMessage ?? "runtime state was not recorded"}`;
|
|
288
|
+
const terminalEventMeta = {
|
|
289
|
+
agent: input.agent,
|
|
290
|
+
habitName: input.habitName,
|
|
291
|
+
trigger: input.trigger,
|
|
292
|
+
runId,
|
|
293
|
+
lifecycle,
|
|
294
|
+
receiptWritten: completion.receiptWritten,
|
|
295
|
+
runtimeStateRecorded: completion.runtimeStateRecorded,
|
|
296
|
+
};
|
|
297
|
+
if (lifecycle === "completed") {
|
|
298
|
+
(0, runtime_1.emitNervesEvent)({
|
|
299
|
+
component: "rsvp",
|
|
300
|
+
event: "rsvp.native_habit_end",
|
|
301
|
+
message,
|
|
302
|
+
meta: terminalEventMeta,
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
else {
|
|
306
|
+
(0, runtime_1.emitNervesEvent)({
|
|
307
|
+
level: "error",
|
|
308
|
+
component: "rsvp",
|
|
309
|
+
event: "rsvp.native_habit_error",
|
|
310
|
+
message,
|
|
311
|
+
meta: terminalEventMeta,
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
return {
|
|
315
|
+
ok,
|
|
316
|
+
message,
|
|
317
|
+
lifecycle,
|
|
318
|
+
runId,
|
|
319
|
+
payload,
|
|
320
|
+
};
|
|
321
|
+
}
|