@ouro.bot/cli 0.1.0-alpha.104 → 0.1.0-alpha.106
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 +14 -0
- package/dist/heart/active-work.js +160 -31
- package/dist/heart/commitments.js +0 -4
- package/dist/mind/obligation-steering.js +11 -107
- package/dist/mind/prompt.js +12 -0
- package/dist/senses/pipeline.js +0 -24
- package/package.json +1 -1
package/changelog.json
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
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.106",
|
|
6
|
+
"changes": [
|
|
7
|
+
"Family-scoped status answers now come from the live obligation/session world-state directly instead of a regex-triggered 'status question' mode, so agents can answer naturally while still seeing all material live work across sessions.",
|
|
8
|
+
"Raw inbound text no longer masquerades as a real commitment or next action; current lanes, artifacts, and next steps are now grounded in persistent obligations, live coding state, and concrete session activity."
|
|
9
|
+
]
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"version": "0.1.0-alpha.105",
|
|
13
|
+
"changes": [
|
|
14
|
+
"Family-wide status answers now dedupe normalized session keys, drop inner/self noise, and ignore stale non-obligation lanes so 'what are you doing?' stays focused on real active work across all live sessions.",
|
|
15
|
+
"BlueBubbles and CLI lanes that refer to the same live thread now collapse into one clean status line, preventing duplicate session bullets when family asks for the full cross-session picture."
|
|
16
|
+
]
|
|
17
|
+
},
|
|
4
18
|
{
|
|
5
19
|
"version": "0.1.0-alpha.104",
|
|
6
20
|
"changes": [
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatOtherActiveSessionSummaries = formatOtherActiveSessionSummaries;
|
|
3
4
|
exports.suggestBridgeForActiveWork = suggestBridgeForActiveWork;
|
|
4
5
|
exports.buildActiveWorkFrame = buildActiveWorkFrame;
|
|
5
6
|
exports.formatActiveWorkFrame = formatActiveWorkFrame;
|
|
@@ -7,6 +8,7 @@ const runtime_1 = require("../nerves/runtime");
|
|
|
7
8
|
const state_machine_1 = require("./bridges/state-machine");
|
|
8
9
|
const obligations_1 = require("./obligations");
|
|
9
10
|
const target_resolution_1 = require("./target-resolution");
|
|
11
|
+
const config_1 = require("./config");
|
|
10
12
|
function activityPriority(source) {
|
|
11
13
|
return source === "friend-facing" ? 0 : 1;
|
|
12
14
|
}
|
|
@@ -28,9 +30,9 @@ function isActiveBridge(bridge) {
|
|
|
28
30
|
return bridge.lifecycle === "active";
|
|
29
31
|
}
|
|
30
32
|
function hasSharedObligationPressure(input) {
|
|
31
|
-
return
|
|
32
|
-
|
|
33
|
-
||
|
|
33
|
+
return input.mustResolveBeforeHandoff
|
|
34
|
+
|| summarizeLiveTasks(input.taskBoard).length > 0
|
|
35
|
+
|| activeObligationCount(input.pendingObligations) > 0;
|
|
34
36
|
}
|
|
35
37
|
function formatCodingLaneLabel(session) {
|
|
36
38
|
return `${session.runner} ${session.id}`;
|
|
@@ -86,6 +88,16 @@ function findPrimaryOpenObligation(frame) {
|
|
|
86
88
|
?? (frame.pendingObligations ?? []).find(obligations_1.isOpenObligation)
|
|
87
89
|
?? null;
|
|
88
90
|
}
|
|
91
|
+
function matchesCurrentSession(frame, obligation) {
|
|
92
|
+
return Boolean(frame.currentSession
|
|
93
|
+
&& obligation.origin.friendId === frame.currentSession.friendId
|
|
94
|
+
&& obligation.origin.channel === frame.currentSession.channel
|
|
95
|
+
&& (0, config_1.sanitizeKey)(obligation.origin.key) === (0, config_1.sanitizeKey)(frame.currentSession.key));
|
|
96
|
+
}
|
|
97
|
+
function findCurrentSessionOpenObligation(frame) {
|
|
98
|
+
return (frame.pendingObligations ?? []).find((obligation) => (0, obligations_1.isOpenObligationStatus)(obligation.status) && matchesCurrentSession(frame, obligation))
|
|
99
|
+
?? null;
|
|
100
|
+
}
|
|
89
101
|
function formatActiveLane(frame, obligation) {
|
|
90
102
|
const liveCodingSession = frame.codingSessions?.[0];
|
|
91
103
|
if (liveCodingSession) {
|
|
@@ -94,12 +106,12 @@ function formatActiveLane(frame, obligation) {
|
|
|
94
106
|
if (obligation?.currentSurface?.label) {
|
|
95
107
|
return obligation.currentSurface.label;
|
|
96
108
|
}
|
|
109
|
+
if (obligation && matchesCurrentSession(frame, obligation) && frame.currentSession) {
|
|
110
|
+
return "this same thread";
|
|
111
|
+
}
|
|
97
112
|
if (frame.inner?.job?.status === "running") {
|
|
98
113
|
return "inner dialog";
|
|
99
114
|
}
|
|
100
|
-
if (typeof frame.currentObligation === "string" && frame.currentObligation.trim().length > 0 && frame.currentSession) {
|
|
101
|
-
return "this same thread";
|
|
102
|
-
}
|
|
103
115
|
return null;
|
|
104
116
|
}
|
|
105
117
|
function formatCurrentArtifact(frame, obligation) {
|
|
@@ -112,11 +124,17 @@ function formatCurrentArtifact(frame, obligation) {
|
|
|
112
124
|
if ((frame.codingSessions ?? []).length > 0) {
|
|
113
125
|
return "no PR or merge artifact yet";
|
|
114
126
|
}
|
|
115
|
-
if (
|
|
127
|
+
if (obligation) {
|
|
116
128
|
return "no artifact yet";
|
|
117
129
|
}
|
|
118
130
|
return null;
|
|
119
131
|
}
|
|
132
|
+
function formatObligationContentNextAction(obligation) {
|
|
133
|
+
const content = obligation?.content?.trim();
|
|
134
|
+
if (!content)
|
|
135
|
+
return null;
|
|
136
|
+
return `work on "${content}" and bring back a concrete artifact`;
|
|
137
|
+
}
|
|
120
138
|
function formatNextAction(frame, obligation) {
|
|
121
139
|
if (obligation?.nextAction?.trim()) {
|
|
122
140
|
return obligation.nextAction.trim();
|
|
@@ -138,13 +156,128 @@ function formatNextAction(frame, obligation) {
|
|
|
138
156
|
return "update runtime, verify version/changelog, then re-observe";
|
|
139
157
|
}
|
|
140
158
|
if (obligation) {
|
|
141
|
-
return "continue the active loop and bring the result back here";
|
|
159
|
+
return formatObligationContentNextAction(obligation) || "continue the active loop and bring the result back here";
|
|
142
160
|
}
|
|
143
|
-
if (
|
|
144
|
-
return
|
|
161
|
+
if (frame.mustResolveBeforeHandoff) {
|
|
162
|
+
return "finish what i started here before moving on";
|
|
145
163
|
}
|
|
146
164
|
return null;
|
|
147
165
|
}
|
|
166
|
+
const RECENT_OTHER_LIVE_SESSION_WINDOW_MS = 60 * 60 * 1000;
|
|
167
|
+
function sessionOriginKey(origin) {
|
|
168
|
+
return `${origin.friendId}/${origin.channel}/${(0, config_1.sanitizeKey)(origin.key)}`;
|
|
169
|
+
}
|
|
170
|
+
function codingSessionTimestampMs(session) {
|
|
171
|
+
return Date.parse(session.lastActivityAt ?? session.startedAt);
|
|
172
|
+
}
|
|
173
|
+
function obligationTimestampMs(obligation) {
|
|
174
|
+
return Date.parse(obligation.updatedAt ?? obligation.createdAt);
|
|
175
|
+
}
|
|
176
|
+
function newestObligationFirst(left, right) {
|
|
177
|
+
return obligationTimestampMs(right) - obligationTimestampMs(left);
|
|
178
|
+
}
|
|
179
|
+
function formatOtherSessionArtifact(obligation, codingSession) {
|
|
180
|
+
if (obligation?.currentArtifact?.trim())
|
|
181
|
+
return obligation.currentArtifact.trim();
|
|
182
|
+
if (obligation?.currentSurface?.kind === "merge" && obligation.currentSurface.label.trim()) {
|
|
183
|
+
return obligation.currentSurface.label.trim();
|
|
184
|
+
}
|
|
185
|
+
if (codingSession)
|
|
186
|
+
return "no PR or merge artifact yet";
|
|
187
|
+
return obligation ? "no artifact yet" : "no explicit artifact yet";
|
|
188
|
+
}
|
|
189
|
+
function formatOtherSessionNextAction(obligation, codingSession) {
|
|
190
|
+
if (obligation?.nextAction?.trim())
|
|
191
|
+
return obligation.nextAction.trim();
|
|
192
|
+
if (obligation?.status === "waiting_for_merge") {
|
|
193
|
+
return `wait for checks, merge ${formatMergeArtifact(obligation)}, then update runtime`;
|
|
194
|
+
}
|
|
195
|
+
if (obligation?.status === "updating_runtime") {
|
|
196
|
+
return "update runtime, verify version/changelog, then re-observe";
|
|
197
|
+
}
|
|
198
|
+
if (codingSession?.status === "waiting_input") {
|
|
199
|
+
return `answer ${formatCodingLaneLabel(codingSession)} and continue`;
|
|
200
|
+
}
|
|
201
|
+
if (codingSession?.status === "stalled") {
|
|
202
|
+
return `unstick ${formatCodingLaneLabel(codingSession)} and continue`;
|
|
203
|
+
}
|
|
204
|
+
if (codingSession) {
|
|
205
|
+
return "finish the coding pass and bring the result back there";
|
|
206
|
+
}
|
|
207
|
+
if (obligation) {
|
|
208
|
+
return formatObligationContentNextAction(obligation) || "continue the active loop and bring the result back there";
|
|
209
|
+
}
|
|
210
|
+
return "check this session and bring back the latest concrete state";
|
|
211
|
+
}
|
|
212
|
+
function formatOtherSessionLine(label, status, activeLane, artifact, nextAction) {
|
|
213
|
+
return `- ${label}: [${status}] ${activeLane}; artifact ${artifact}; next ${nextAction}`;
|
|
214
|
+
}
|
|
215
|
+
function formatOtherActiveSessionSummaries(frame, nowMs = Date.now()) {
|
|
216
|
+
const originMap = new Map();
|
|
217
|
+
for (const session of frame.friendActivity?.allOtherLiveSessions ?? []) {
|
|
218
|
+
if (session.friendId === "self" || session.channel === "inner")
|
|
219
|
+
continue;
|
|
220
|
+
originMap.set(sessionOriginKey(session), {
|
|
221
|
+
friendId: session.friendId,
|
|
222
|
+
channel: session.channel,
|
|
223
|
+
key: session.key,
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
const orphanCodingSummaries = (frame.otherCodingSessions ?? [])
|
|
227
|
+
.filter((session) => !session.originSession)
|
|
228
|
+
.sort((left, right) => codingSessionTimestampMs(right) - codingSessionTimestampMs(left))
|
|
229
|
+
.map((session) => ({
|
|
230
|
+
timestampMs: codingSessionTimestampMs(session),
|
|
231
|
+
line: formatOtherSessionLine("another session", session.status, formatCodingLaneLabel(session), "no PR or merge artifact yet", formatOtherSessionNextAction(null, session)),
|
|
232
|
+
}));
|
|
233
|
+
for (const session of frame.otherCodingSessions ?? []) {
|
|
234
|
+
if (!session.originSession)
|
|
235
|
+
continue;
|
|
236
|
+
if (frame.currentSession
|
|
237
|
+
&& session.originSession.friendId === frame.currentSession.friendId
|
|
238
|
+
&& session.originSession.channel === frame.currentSession.channel
|
|
239
|
+
&& (0, config_1.sanitizeKey)(session.originSession.key) === (0, config_1.sanitizeKey)(frame.currentSession.key)) {
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
originMap.set(sessionOriginKey(session.originSession), session.originSession);
|
|
243
|
+
}
|
|
244
|
+
for (const obligation of frame.pendingObligations ?? []) {
|
|
245
|
+
if (obligation.status === "fulfilled" || matchesCurrentSession(frame, obligation))
|
|
246
|
+
continue;
|
|
247
|
+
originMap.set(sessionOriginKey(obligation.origin), obligation.origin);
|
|
248
|
+
}
|
|
249
|
+
const summaries = [...originMap.values()].map((origin) => {
|
|
250
|
+
const originKey = sessionOriginKey(origin);
|
|
251
|
+
const obligation = [...(frame.pendingObligations ?? [])]
|
|
252
|
+
.filter((candidate) => candidate.status !== "fulfilled" && sessionOriginKey(candidate.origin) === originKey)
|
|
253
|
+
.sort(newestObligationFirst)[0] ?? null;
|
|
254
|
+
const codingSession = [...(frame.otherCodingSessions ?? [])]
|
|
255
|
+
.filter((candidate) => candidate.originSession && sessionOriginKey(candidate.originSession) === originKey)
|
|
256
|
+
.sort((left, right) => codingSessionTimestampMs(right) - codingSessionTimestampMs(left))[0] ?? null;
|
|
257
|
+
const liveSession = (frame.friendActivity?.allOtherLiveSessions ?? []).find((candidate) => sessionOriginKey(candidate) === originKey) ?? null;
|
|
258
|
+
const hasFreshSessionActivity = liveSession
|
|
259
|
+
? (nowMs - liveSession.lastActivityMs) <= RECENT_OTHER_LIVE_SESSION_WINDOW_MS
|
|
260
|
+
: false;
|
|
261
|
+
if (!obligation && !codingSession && !hasFreshSessionActivity) {
|
|
262
|
+
return null;
|
|
263
|
+
}
|
|
264
|
+
const timestampMs = Math.max(liveSession?.lastActivityMs ?? 0, codingSession ? codingSessionTimestampMs(codingSession) : 0, obligation ? obligationTimestampMs(obligation) : 0);
|
|
265
|
+
const activeLane = codingSession
|
|
266
|
+
? formatCodingLaneLabel(codingSession)
|
|
267
|
+
: obligation?.currentSurface?.label?.trim() || "this live thread";
|
|
268
|
+
const artifact = formatOtherSessionArtifact(obligation, codingSession);
|
|
269
|
+
const nextAction = formatOtherSessionNextAction(obligation, codingSession);
|
|
270
|
+
const status = obligation?.status ?? codingSession?.status ?? "active";
|
|
271
|
+
const label = liveSession?.friendName ?? origin.friendId;
|
|
272
|
+
return {
|
|
273
|
+
timestampMs,
|
|
274
|
+
line: formatOtherSessionLine(`${label}/${origin.channel}/${origin.key}`, status, activeLane, artifact, nextAction),
|
|
275
|
+
};
|
|
276
|
+
}).filter((entry) => entry !== null)
|
|
277
|
+
.sort((left, right) => right.timestampMs - left.timestampMs);
|
|
278
|
+
const lines = summaries.map((entry) => entry.line);
|
|
279
|
+
return [...lines, ...orphanCodingSummaries.map((entry) => entry.line)];
|
|
280
|
+
}
|
|
148
281
|
function suggestBridgeForActiveWork(input) {
|
|
149
282
|
const targetCandidates = (input.targetCandidates ?? [])
|
|
150
283
|
.filter((candidate) => {
|
|
@@ -164,10 +297,17 @@ function suggestBridgeForActiveWork(input) {
|
|
|
164
297
|
.sort((a, b) => {
|
|
165
298
|
return b.lastActivityMs - a.lastActivityMs;
|
|
166
299
|
});
|
|
167
|
-
if (!hasSharedObligationPressure(
|
|
300
|
+
if (!hasSharedObligationPressure({
|
|
301
|
+
mustResolveBeforeHandoff: input.mustResolveBeforeHandoff,
|
|
302
|
+
taskBoard: input.taskBoard,
|
|
303
|
+
pendingObligations: input.pendingObligations,
|
|
304
|
+
}) || targetCandidates.length === 0) {
|
|
168
305
|
return null;
|
|
169
306
|
}
|
|
170
307
|
const targetSession = targetCandidates[0];
|
|
308
|
+
const objectiveHint = [...(input.pendingObligations ?? [])]
|
|
309
|
+
.find((obligation) => (0, obligations_1.isOpenObligationStatus)(obligation.status))
|
|
310
|
+
?.content?.trim() || "keep this shared work aligned";
|
|
171
311
|
const activeBridge = input.bridges.find(isActiveBridge) ?? null;
|
|
172
312
|
if (activeBridge) {
|
|
173
313
|
const alreadyAttached = activeBridge.attachedSessions.some((session) => session.friendId === targetSession.friendId
|
|
@@ -186,7 +326,7 @@ function suggestBridgeForActiveWork(input) {
|
|
|
186
326
|
return {
|
|
187
327
|
kind: "begin-new",
|
|
188
328
|
targetSession,
|
|
189
|
-
objectiveHint
|
|
329
|
+
objectiveHint,
|
|
190
330
|
reason: "shared-work-candidate",
|
|
191
331
|
};
|
|
192
332
|
}
|
|
@@ -237,6 +377,7 @@ function buildActiveWorkFrame(input) {
|
|
|
237
377
|
currentObligation: input.currentObligation,
|
|
238
378
|
mustResolveBeforeHandoff: input.mustResolveBeforeHandoff,
|
|
239
379
|
bridges: input.bridges,
|
|
380
|
+
pendingObligations: input.pendingObligations,
|
|
240
381
|
taskBoard: input.taskBoard,
|
|
241
382
|
targetCandidates: input.targetCandidates,
|
|
242
383
|
}),
|
|
@@ -263,16 +404,16 @@ function buildActiveWorkFrame(input) {
|
|
|
263
404
|
function formatActiveWorkFrame(frame) {
|
|
264
405
|
const lines = ["## what i'm holding"];
|
|
265
406
|
const primaryObligation = findPrimaryOpenObligation(frame);
|
|
407
|
+
const currentSessionObligation = findCurrentSessionOpenObligation(frame);
|
|
266
408
|
const activeLane = formatActiveLane(frame, primaryObligation);
|
|
267
409
|
const currentArtifact = formatCurrentArtifact(frame, primaryObligation);
|
|
268
410
|
const nextAction = formatNextAction(frame, primaryObligation);
|
|
269
|
-
const
|
|
270
|
-
const otherLiveSessions = frame.friendActivity?.allOtherLiveSessions ?? [];
|
|
411
|
+
const otherActiveSessions = formatOtherActiveSessionSummaries(frame);
|
|
271
412
|
// Session line
|
|
272
413
|
if (frame.currentSession) {
|
|
273
414
|
let sessionLine = `i'm in a conversation on ${formatSessionLabel(frame.currentSession)}.`;
|
|
274
|
-
if (
|
|
275
|
-
sessionLine += ` i
|
|
415
|
+
if (currentSessionObligation?.content?.trim()) {
|
|
416
|
+
sessionLine += ` i still owe them: ${currentSessionObligation.content.trim()}.`;
|
|
276
417
|
}
|
|
277
418
|
else if (frame.mustResolveBeforeHandoff) {
|
|
278
419
|
sessionLine += " i need to finish what i started here before moving on.";
|
|
@@ -340,22 +481,10 @@ function formatActiveWorkFrame(frame) {
|
|
|
340
481
|
lines.push(`- [${session.status}] ${formatCodingLaneLabel(session)}${describeCodingSessionScope(session, frame.currentSession)}`);
|
|
341
482
|
}
|
|
342
483
|
}
|
|
343
|
-
if (
|
|
484
|
+
if (otherActiveSessions.length > 0) {
|
|
344
485
|
lines.push("");
|
|
345
|
-
lines.push("## other
|
|
346
|
-
|
|
347
|
-
const origin = session.originSession
|
|
348
|
-
? `${session.originSession.friendId}/${session.originSession.channel}/${session.originSession.key}`
|
|
349
|
-
: "another session";
|
|
350
|
-
lines.push(`- [${session.status}] ${formatCodingLaneLabel(session)} for ${origin}`);
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
if (otherLiveSessions.length > 0) {
|
|
354
|
-
lines.push("");
|
|
355
|
-
lines.push("## other live sessions");
|
|
356
|
-
for (const session of otherLiveSessions) {
|
|
357
|
-
lines.push(`- ${session.friendName}/${session.channel}/${session.key}`);
|
|
358
|
-
}
|
|
486
|
+
lines.push("## other active sessions");
|
|
487
|
+
lines.push(...otherActiveSessions);
|
|
359
488
|
}
|
|
360
489
|
// Task pressure
|
|
361
490
|
if ((frame.taskPressure?.liveTaskNames ?? []).length > 0) {
|
|
@@ -34,10 +34,6 @@ function deriveCommitments(activeWorkFrame, innerJob, pendingObligations) {
|
|
|
34
34
|
completionCriteria.push("close my active obligation loops");
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
|
-
// Obligation (from current turn -- kept for backward compat)
|
|
38
|
-
if (typeof activeWorkFrame.currentObligation === "string" && activeWorkFrame.currentObligation.trim().length > 0) {
|
|
39
|
-
committedTo.push(`i told them i'd ${activeWorkFrame.currentObligation.trim()}`);
|
|
40
|
-
}
|
|
41
37
|
// Inner job
|
|
42
38
|
if (innerJob.status === "queued" || innerJob.status === "running") {
|
|
43
39
|
const contentSuffix = innerJob.content ? ` -- ${innerJob.content.slice(0, 60)}` : "";
|
|
@@ -7,6 +7,8 @@ exports.renderConcreteStatusGuidance = renderConcreteStatusGuidance;
|
|
|
7
7
|
exports.renderLiveThreadStatusShape = renderLiveThreadStatusShape;
|
|
8
8
|
exports.buildExactStatusReply = buildExactStatusReply;
|
|
9
9
|
exports.renderExactStatusReplyContract = renderExactStatusReplyContract;
|
|
10
|
+
const config_1 = require("../heart/config");
|
|
11
|
+
const active_work_1 = require("../heart/active-work");
|
|
10
12
|
const runtime_1 = require("../nerves/runtime");
|
|
11
13
|
function findActivePersistentObligation(frame) {
|
|
12
14
|
if (!frame)
|
|
@@ -26,96 +28,7 @@ function matchesSessionOrigin(frame, origin) {
|
|
|
26
28
|
return Boolean(frame.currentSession
|
|
27
29
|
&& origin.friendId === frame.currentSession.friendId
|
|
28
30
|
&& origin.channel === frame.currentSession.channel
|
|
29
|
-
&& origin.key === frame.currentSession.key);
|
|
30
|
-
}
|
|
31
|
-
function sessionOriginKey(origin) {
|
|
32
|
-
return `${origin.friendId}/${origin.channel}/${origin.key}`;
|
|
33
|
-
}
|
|
34
|
-
function codingSessionTimestampMs(session) {
|
|
35
|
-
return Date.parse(session.lastActivityAt ?? session.startedAt);
|
|
36
|
-
}
|
|
37
|
-
function formatCodingLaneLabel(session) {
|
|
38
|
-
return `${session.runner} ${session.id}`;
|
|
39
|
-
}
|
|
40
|
-
function formatOtherSessionArtifact(obligation, codingSession) {
|
|
41
|
-
if (obligation?.currentArtifact?.trim())
|
|
42
|
-
return obligation.currentArtifact.trim();
|
|
43
|
-
if (obligation?.currentSurface?.kind === "merge" && obligation.currentSurface.label.trim()) {
|
|
44
|
-
return obligation.currentSurface.label.trim();
|
|
45
|
-
}
|
|
46
|
-
if (codingSession)
|
|
47
|
-
return "no PR or merge artifact yet";
|
|
48
|
-
return "no artifact yet";
|
|
49
|
-
}
|
|
50
|
-
function formatOtherSessionNextAction(obligation, codingSession) {
|
|
51
|
-
if (obligation?.nextAction?.trim())
|
|
52
|
-
return obligation.nextAction.trim();
|
|
53
|
-
if (obligation?.status === "waiting_for_merge") {
|
|
54
|
-
return `wait for checks, merge ${formatMergeArtifact(obligation)}, then update runtime`;
|
|
55
|
-
}
|
|
56
|
-
if (obligation?.status === "updating_runtime") {
|
|
57
|
-
return "update runtime, verify version/changelog, then re-observe";
|
|
58
|
-
}
|
|
59
|
-
if (codingSession?.status === "waiting_input") {
|
|
60
|
-
return `answer ${formatCodingLaneLabel(codingSession)} and continue`;
|
|
61
|
-
}
|
|
62
|
-
if (codingSession?.status === "stalled") {
|
|
63
|
-
return `unstick ${formatCodingLaneLabel(codingSession)} and continue`;
|
|
64
|
-
}
|
|
65
|
-
if (codingSession) {
|
|
66
|
-
return "finish the coding pass and bring the result back there";
|
|
67
|
-
}
|
|
68
|
-
if (obligation) {
|
|
69
|
-
return "continue the active loop and bring the result back there";
|
|
70
|
-
}
|
|
71
|
-
return "check this session and bring back the latest concrete state";
|
|
72
|
-
}
|
|
73
|
-
function findFriendNameForOrigin(frame, origin) {
|
|
74
|
-
return (frame.friendActivity?.allOtherLiveSessions ?? []).find((entry) => entry.friendId === origin.friendId
|
|
75
|
-
&& entry.channel === origin.channel
|
|
76
|
-
&& entry.key === origin.key)?.friendName ?? origin.friendId;
|
|
77
|
-
}
|
|
78
|
-
function buildOtherActiveSessionLines(frame) {
|
|
79
|
-
const originMap = new Map();
|
|
80
|
-
for (const session of frame.friendActivity?.allOtherLiveSessions ?? []) {
|
|
81
|
-
originMap.set(sessionOriginKey(session), {
|
|
82
|
-
friendId: session.friendId,
|
|
83
|
-
channel: session.channel,
|
|
84
|
-
key: session.key,
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
for (const session of frame.otherCodingSessions ?? []) {
|
|
88
|
-
if (!session.originSession || matchesSessionOrigin(frame, session.originSession))
|
|
89
|
-
continue;
|
|
90
|
-
originMap.set(sessionOriginKey(session.originSession), session.originSession);
|
|
91
|
-
}
|
|
92
|
-
for (const obligation of frame.pendingObligations ?? []) {
|
|
93
|
-
if (obligation.status === "fulfilled" || matchesSessionOrigin(frame, obligation.origin))
|
|
94
|
-
continue;
|
|
95
|
-
originMap.set(sessionOriginKey(obligation.origin), obligation.origin);
|
|
96
|
-
}
|
|
97
|
-
const summaries = [...originMap.values()].map((origin) => {
|
|
98
|
-
const obligation = [...(frame.pendingObligations ?? [])]
|
|
99
|
-
.filter((candidate) => candidate.status !== "fulfilled" && sessionOriginKey(candidate.origin) === sessionOriginKey(origin))
|
|
100
|
-
.sort(newestObligationFirst)[0] ?? null;
|
|
101
|
-
const codingSession = [...(frame.otherCodingSessions ?? [])]
|
|
102
|
-
.filter((candidate) => candidate.originSession && sessionOriginKey(candidate.originSession) === sessionOriginKey(origin))
|
|
103
|
-
.sort((left, right) => codingSessionTimestampMs(right) - codingSessionTimestampMs(left))[0] ?? null;
|
|
104
|
-
const liveSession = (frame.friendActivity?.allOtherLiveSessions ?? []).find((candidate) => sessionOriginKey(candidate) === sessionOriginKey(origin)) ?? null;
|
|
105
|
-
const timestampMs = Math.max(liveSession?.lastActivityMs ?? 0, codingSession ? codingSessionTimestampMs(codingSession) : 0, obligation ? obligationTimestampMs(obligation) : 0);
|
|
106
|
-
const activeLane = codingSession
|
|
107
|
-
? formatCodingLaneLabel(codingSession)
|
|
108
|
-
: obligation?.currentSurface?.label?.trim() || "this live thread";
|
|
109
|
-
const artifact = formatOtherSessionArtifact(obligation, codingSession);
|
|
110
|
-
const nextAction = formatOtherSessionNextAction(obligation, codingSession);
|
|
111
|
-
const status = obligation?.status ?? codingSession?.status ?? "active";
|
|
112
|
-
const friendName = findFriendNameForOrigin(frame, origin);
|
|
113
|
-
return {
|
|
114
|
-
timestampMs,
|
|
115
|
-
line: `- ${friendName}/${origin.channel}/${origin.key}: [${status}] ${activeLane}; artifact ${artifact}; next ${nextAction}`,
|
|
116
|
-
};
|
|
117
|
-
}).sort((left, right) => right.timestampMs - left.timestampMs);
|
|
118
|
-
return summaries.length > 0 ? summaries.map((entry) => entry.line) : ["- none"];
|
|
31
|
+
&& (0, config_1.sanitizeKey)(origin.key) === (0, config_1.sanitizeKey)(frame.currentSession.key));
|
|
119
32
|
}
|
|
120
33
|
function findStatusObligation(frame) {
|
|
121
34
|
if (!frame)
|
|
@@ -188,30 +101,20 @@ function formatActiveLane(frame, obligation) {
|
|
|
188
101
|
: `${liveCodingSession.runner} ${liveCodingSession.id}`;
|
|
189
102
|
}
|
|
190
103
|
return obligation.currentSurface?.label
|
|
191
|
-
|| (frame
|
|
104
|
+
|| (matchesCurrentSession(frame, obligation) ? "this same thread" : "this live loop");
|
|
192
105
|
}
|
|
193
106
|
function formatCurrentArtifact(frame, obligation) {
|
|
194
107
|
if (obligation?.currentArtifact)
|
|
195
108
|
return obligation.currentArtifact;
|
|
196
109
|
if (obligation?.currentSurface?.kind === "merge")
|
|
197
110
|
return obligation.currentSurface.label;
|
|
198
|
-
if (frame.currentObligation?.trim())
|
|
199
|
-
return "no artifact yet";
|
|
200
111
|
if ((frame.codingSessions ?? []).length > 0)
|
|
201
112
|
return "no PR or merge artifact yet";
|
|
202
|
-
return obligation ? "no
|
|
203
|
-
}
|
|
204
|
-
function isStatusCheckPrompt(text) {
|
|
205
|
-
const trimmed = text?.trim();
|
|
206
|
-
if (!trimmed)
|
|
207
|
-
return false;
|
|
208
|
-
return /^(what are you doing|what(?:'|’)s your status|status|status update|what changed|where are you at|where things stand)\??$/i.test(trimmed);
|
|
113
|
+
return obligation ? "no artifact yet" : "";
|
|
209
114
|
}
|
|
210
115
|
function formatNextAction(frame, obligation) {
|
|
211
116
|
if (obligation?.nextAction)
|
|
212
117
|
return obligation.nextAction;
|
|
213
|
-
const currentObligation = frame.currentObligation?.trim() ?? "";
|
|
214
|
-
const statusCheckPrompt = isStatusCheckPrompt(currentObligation);
|
|
215
118
|
const liveCodingSession = frame.codingSessions?.[0];
|
|
216
119
|
if (liveCodingSession?.status === "waiting_input") {
|
|
217
120
|
return `answer ${liveCodingSession.runner} ${liveCodingSession.id} and continue`;
|
|
@@ -228,13 +131,13 @@ function formatNextAction(frame, obligation) {
|
|
|
228
131
|
if (obligation?.status === "updating_runtime") {
|
|
229
132
|
return "update runtime, verify version/changelog, then re-observe";
|
|
230
133
|
}
|
|
231
|
-
if (
|
|
232
|
-
return `work on "${
|
|
134
|
+
if (obligation?.content?.trim()) {
|
|
135
|
+
return `work on "${obligation.content.trim()}" and bring back a concrete artifact`;
|
|
233
136
|
}
|
|
234
137
|
return obligation ? "continue the active loop and bring the result back here" : "";
|
|
235
138
|
}
|
|
236
139
|
function renderConcreteStatusGuidance(frame, obligation) {
|
|
237
|
-
const activeLane = obligation ? formatActiveLane(frame, obligation) :
|
|
140
|
+
const activeLane = obligation ? formatActiveLane(frame, obligation) : "";
|
|
238
141
|
const currentArtifact = formatCurrentArtifact(frame, obligation);
|
|
239
142
|
const nextAction = formatNextAction(frame, obligation);
|
|
240
143
|
const liveConversation = frame.currentSession
|
|
@@ -249,7 +152,7 @@ the current artifact is ${currentArtifact}.
|
|
|
249
152
|
if i just finished or verified something concrete in this live lane, i name that as the latest checkpoint.
|
|
250
153
|
the next action is ${nextAction}.
|
|
251
154
|
|
|
252
|
-
i
|
|
155
|
+
i answer naturally from those facts instead of forcing a canned status block.`;
|
|
253
156
|
}
|
|
254
157
|
function renderLiveThreadStatusShape(frame) {
|
|
255
158
|
if (!frame.currentSession)
|
|
@@ -288,7 +191,8 @@ function buildExactStatusReply(frame, obligation, latestCheckpoint, statusCheckS
|
|
|
288
191
|
];
|
|
289
192
|
if (statusCheckScope === "all-sessions-family") {
|
|
290
193
|
lines.push("other active sessions:");
|
|
291
|
-
|
|
194
|
+
const summaries = (0, active_work_1.formatOtherActiveSessionSummaries)(frame);
|
|
195
|
+
lines.push(...(summaries.length > 0 ? summaries : ["- none"]));
|
|
292
196
|
}
|
|
293
197
|
return lines.join("\n");
|
|
294
198
|
}
|
package/dist/mind/prompt.js
CHANGED
|
@@ -457,6 +457,17 @@ function activeWorkSection(options) {
|
|
|
457
457
|
return "";
|
|
458
458
|
return (0, active_work_1.formatActiveWorkFrame)(options.activeWorkFrame);
|
|
459
459
|
}
|
|
460
|
+
function familyCrossSessionTruthSection(context, options) {
|
|
461
|
+
if (!options?.activeWorkFrame)
|
|
462
|
+
return "";
|
|
463
|
+
if (context?.friend?.trustLevel !== "family")
|
|
464
|
+
return "";
|
|
465
|
+
return `## cross-session truth
|
|
466
|
+
if a family member asks what i'm up to or how things are going, that includes the material live work i can see across sessions, not just this thread.
|
|
467
|
+
i answer naturally from the live world-state in this prompt.
|
|
468
|
+
i do not rely on canned status-question modes or phrase matching.
|
|
469
|
+
if part of the picture is still fuzzy, i say what i can see and what still needs checking.`;
|
|
470
|
+
}
|
|
460
471
|
function centerOfGravitySteeringSection(channel, options) {
|
|
461
472
|
if (channel === "inner")
|
|
462
473
|
return "";
|
|
@@ -753,6 +764,7 @@ async function buildSystem(channel = "cli", options, context) {
|
|
|
753
764
|
skillsSection(),
|
|
754
765
|
taskBoardSection(),
|
|
755
766
|
activeWorkSection(options),
|
|
767
|
+
familyCrossSessionTruthSection(context, options),
|
|
756
768
|
statusCheckSection(channel, options),
|
|
757
769
|
centerOfGravitySteeringSection(channel, options),
|
|
758
770
|
commitmentsSection(options),
|
package/dist/senses/pipeline.js
CHANGED
|
@@ -38,23 +38,6 @@ function emptyTaskBoard() {
|
|
|
38
38
|
activeBridges: [],
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
|
-
const STATUS_CHECK_PATTERNS = [
|
|
42
|
-
/^\s*what are you doing\??\s*$/i,
|
|
43
|
-
/^\s*what'?s your status\??\s*$/i,
|
|
44
|
-
/^\s*status\??\s*$/i,
|
|
45
|
-
/^\s*status update\??\s*$/i,
|
|
46
|
-
/^\s*what changed\??\s*$/i,
|
|
47
|
-
/^\s*where (?:are you at|things stand)\??\s*$/i,
|
|
48
|
-
];
|
|
49
|
-
function isStatusCheckRequested(ingressTexts) {
|
|
50
|
-
const latest = ingressTexts
|
|
51
|
-
?.map((text) => text.trim())
|
|
52
|
-
.filter((text) => text.length > 0)
|
|
53
|
-
.at(-1);
|
|
54
|
-
if (!latest)
|
|
55
|
-
return false;
|
|
56
|
-
return STATUS_CHECK_PATTERNS.some((pattern) => pattern.test(latest));
|
|
57
|
-
}
|
|
58
41
|
function isLiveCodingSessionStatus(status) {
|
|
59
42
|
return status === "spawning"
|
|
60
43
|
|| status === "running"
|
|
@@ -293,10 +276,6 @@ async function handleInboundTurn(input) {
|
|
|
293
276
|
}
|
|
294
277
|
// Step 5: runAgent
|
|
295
278
|
const existingToolContext = input.runAgentOptions?.toolContext;
|
|
296
|
-
const statusCheckRequested = isStatusCheckRequested(input.continuityIngressTexts);
|
|
297
|
-
const statusCheckScope = statusCheckRequested && resolvedContext.friend.trustLevel === "family"
|
|
298
|
-
? "all-sessions-family"
|
|
299
|
-
: undefined;
|
|
300
279
|
const runAgentOptions = {
|
|
301
280
|
...input.runAgentOptions,
|
|
302
281
|
bridgeContext,
|
|
@@ -304,9 +283,6 @@ async function handleInboundTurn(input) {
|
|
|
304
283
|
delegationDecision,
|
|
305
284
|
currentSessionKey: currentSession.key,
|
|
306
285
|
currentObligation,
|
|
307
|
-
statusCheckRequested,
|
|
308
|
-
statusCheckScope,
|
|
309
|
-
toolChoiceRequired: statusCheckRequested ? true : input.runAgentOptions?.toolChoiceRequired,
|
|
310
286
|
mustResolveBeforeHandoff,
|
|
311
287
|
setMustResolveBeforeHandoff: (value) => {
|
|
312
288
|
mustResolveBeforeHandoff = value;
|