@ouro.bot/cli 0.1.0-alpha.105 → 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 CHANGED
@@ -1,6 +1,13 @@
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
+ },
4
11
  {
5
12
  "version": "0.1.0-alpha.105",
6
13
  "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 (typeof input.currentObligation === "string"
32
- && input.currentObligation.trim().length > 0) || input.mustResolveBeforeHandoff
33
- || summarizeLiveTasks(input.taskBoard).length > 0;
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 (typeof frame.currentObligation === "string" && frame.currentObligation.trim().length > 0) {
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 (typeof frame.currentObligation === "string" && frame.currentObligation.trim().length > 0) {
144
- return `work on "${frame.currentObligation.trim()}" and bring back a concrete artifact`;
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(input) || targetCandidates.length === 0) {
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: input.currentObligation?.trim() || "keep this shared work aligned",
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 otherCodingSessions = frame.otherCodingSessions ?? [];
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 (typeof frame.currentObligation === "string" && frame.currentObligation.trim().length > 0) {
275
- sessionLine += ` i told them i'd ${frame.currentObligation.trim()}.`;
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 (otherCodingSessions.length > 0) {
484
+ if (otherActiveSessions.length > 0) {
344
485
  lines.push("");
345
- lines.push("## other live coding work");
346
- for (const session of otherCodingSessions) {
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)}` : "";
@@ -8,8 +8,8 @@ exports.renderLiveThreadStatusShape = renderLiveThreadStatusShape;
8
8
  exports.buildExactStatusReply = buildExactStatusReply;
9
9
  exports.renderExactStatusReplyContract = renderExactStatusReplyContract;
10
10
  const config_1 = require("../heart/config");
11
+ const active_work_1 = require("../heart/active-work");
11
12
  const runtime_1 = require("../nerves/runtime");
12
- const RECENT_OTHER_LIVE_SESSION_WINDOW_MS = 60 * 60 * 1000;
13
13
  function findActivePersistentObligation(frame) {
14
14
  if (!frame)
15
15
  return null;
@@ -30,102 +30,6 @@ function matchesSessionOrigin(frame, origin) {
30
30
  && origin.channel === frame.currentSession.channel
31
31
  && (0, config_1.sanitizeKey)(origin.key) === (0, config_1.sanitizeKey)(frame.currentSession.key));
32
32
  }
33
- function sessionOriginKey(origin) {
34
- return `${origin.friendId}/${origin.channel}/${(0, config_1.sanitizeKey)(origin.key)}`;
35
- }
36
- function codingSessionTimestampMs(session) {
37
- return Date.parse(session.lastActivityAt ?? session.startedAt);
38
- }
39
- function formatCodingLaneLabel(session) {
40
- return `${session.runner} ${session.id}`;
41
- }
42
- function formatOtherSessionArtifact(obligation, codingSession) {
43
- if (obligation?.currentArtifact?.trim())
44
- return obligation.currentArtifact.trim();
45
- if (obligation?.currentSurface?.kind === "merge" && obligation.currentSurface.label.trim()) {
46
- return obligation.currentSurface.label.trim();
47
- }
48
- if (codingSession)
49
- return "no PR or merge artifact yet";
50
- return "no artifact yet";
51
- }
52
- function formatOtherSessionNextAction(obligation, codingSession) {
53
- if (obligation?.nextAction?.trim())
54
- return obligation.nextAction.trim();
55
- if (obligation?.status === "waiting_for_merge") {
56
- return `wait for checks, merge ${formatMergeArtifact(obligation)}, then update runtime`;
57
- }
58
- if (obligation?.status === "updating_runtime") {
59
- return "update runtime, verify version/changelog, then re-observe";
60
- }
61
- if (codingSession?.status === "waiting_input") {
62
- return `answer ${formatCodingLaneLabel(codingSession)} and continue`;
63
- }
64
- if (codingSession?.status === "stalled") {
65
- return `unstick ${formatCodingLaneLabel(codingSession)} and continue`;
66
- }
67
- if (codingSession) {
68
- return "finish the coding pass and bring the result back there";
69
- }
70
- if (obligation) {
71
- return "continue the active loop and bring the result back there";
72
- }
73
- return "check this session and bring back the latest concrete state";
74
- }
75
- function findFriendNameForOrigin(frame, origin) {
76
- return (frame.friendActivity?.allOtherLiveSessions ?? []).find((entry) => sessionOriginKey(entry) === sessionOriginKey(origin))?.friendName ?? origin.friendId;
77
- }
78
- function buildOtherActiveSessionLines(frame) {
79
- const originMap = new Map();
80
- for (const session of frame.friendActivity?.allOtherLiveSessions ?? []) {
81
- if (session.friendId === "self" || session.channel === "inner")
82
- continue;
83
- originMap.set(sessionOriginKey(session), {
84
- friendId: session.friendId,
85
- channel: session.channel,
86
- key: session.key,
87
- });
88
- }
89
- for (const session of frame.otherCodingSessions ?? []) {
90
- if (!session.originSession || matchesSessionOrigin(frame, session.originSession))
91
- continue;
92
- originMap.set(sessionOriginKey(session.originSession), session.originSession);
93
- }
94
- for (const obligation of frame.pendingObligations ?? []) {
95
- if (obligation.status === "fulfilled" || matchesSessionOrigin(frame, obligation.origin))
96
- continue;
97
- originMap.set(sessionOriginKey(obligation.origin), obligation.origin);
98
- }
99
- const summaries = [...originMap.values()].map((origin) => {
100
- const obligation = [...(frame.pendingObligations ?? [])]
101
- .filter((candidate) => candidate.status !== "fulfilled" && sessionOriginKey(candidate.origin) === sessionOriginKey(origin))
102
- .sort(newestObligationFirst)[0] ?? null;
103
- const codingSession = [...(frame.otherCodingSessions ?? [])]
104
- .filter((candidate) => candidate.originSession && sessionOriginKey(candidate.originSession) === sessionOriginKey(origin))
105
- .sort((left, right) => codingSessionTimestampMs(right) - codingSessionTimestampMs(left))[0] ?? null;
106
- const liveSession = (frame.friendActivity?.allOtherLiveSessions ?? []).find((candidate) => sessionOriginKey(candidate) === sessionOriginKey(origin)) ?? null;
107
- const hasFreshSessionActivity = liveSession
108
- ? (Date.now() - liveSession.lastActivityMs) <= RECENT_OTHER_LIVE_SESSION_WINDOW_MS
109
- : false;
110
- if (!obligation && !codingSession && !hasFreshSessionActivity) {
111
- return null;
112
- }
113
- const timestampMs = Math.max(liveSession?.lastActivityMs ?? 0, codingSession ? codingSessionTimestampMs(codingSession) : 0, obligation ? obligationTimestampMs(obligation) : 0);
114
- const activeLane = codingSession
115
- ? formatCodingLaneLabel(codingSession)
116
- : obligation?.currentSurface?.label?.trim() || "this live thread";
117
- const artifact = formatOtherSessionArtifact(obligation, codingSession);
118
- const nextAction = formatOtherSessionNextAction(obligation, codingSession);
119
- const status = obligation?.status ?? codingSession?.status ?? "active";
120
- const friendName = findFriendNameForOrigin(frame, origin);
121
- return {
122
- timestampMs,
123
- line: `- ${friendName}/${origin.channel}/${origin.key}: [${status}] ${activeLane}; artifact ${artifact}; next ${nextAction}`,
124
- };
125
- }).filter((entry) => entry !== null)
126
- .sort((left, right) => right.timestampMs - left.timestampMs);
127
- return summaries.length > 0 ? summaries.map((entry) => entry.line) : ["- none"];
128
- }
129
33
  function findStatusObligation(frame) {
130
34
  if (!frame)
131
35
  return null;
@@ -197,30 +101,20 @@ function formatActiveLane(frame, obligation) {
197
101
  : `${liveCodingSession.runner} ${liveCodingSession.id}`;
198
102
  }
199
103
  return obligation.currentSurface?.label
200
- || (frame.currentObligation?.trim() ? "this same thread" : "this live loop");
104
+ || (matchesCurrentSession(frame, obligation) ? "this same thread" : "this live loop");
201
105
  }
202
106
  function formatCurrentArtifact(frame, obligation) {
203
107
  if (obligation?.currentArtifact)
204
108
  return obligation.currentArtifact;
205
109
  if (obligation?.currentSurface?.kind === "merge")
206
110
  return obligation.currentSurface.label;
207
- if (frame.currentObligation?.trim())
208
- return "no artifact yet";
209
111
  if ((frame.codingSessions ?? []).length > 0)
210
112
  return "no PR or merge artifact yet";
211
- return obligation ? "no explicit artifact yet" : "";
212
- }
213
- function isStatusCheckPrompt(text) {
214
- const trimmed = text?.trim();
215
- if (!trimmed)
216
- return false;
217
- 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" : "";
218
114
  }
219
115
  function formatNextAction(frame, obligation) {
220
116
  if (obligation?.nextAction)
221
117
  return obligation.nextAction;
222
- const currentObligation = frame.currentObligation?.trim() ?? "";
223
- const statusCheckPrompt = isStatusCheckPrompt(currentObligation);
224
118
  const liveCodingSession = frame.codingSessions?.[0];
225
119
  if (liveCodingSession?.status === "waiting_input") {
226
120
  return `answer ${liveCodingSession.runner} ${liveCodingSession.id} and continue`;
@@ -237,13 +131,13 @@ function formatNextAction(frame, obligation) {
237
131
  if (obligation?.status === "updating_runtime") {
238
132
  return "update runtime, verify version/changelog, then re-observe";
239
133
  }
240
- if (currentObligation && !statusCheckPrompt) {
241
- return `work on "${currentObligation}" and bring back a concrete artifact`;
134
+ if (obligation?.content?.trim()) {
135
+ return `work on "${obligation.content.trim()}" and bring back a concrete artifact`;
242
136
  }
243
137
  return obligation ? "continue the active loop and bring the result back here" : "";
244
138
  }
245
139
  function renderConcreteStatusGuidance(frame, obligation) {
246
- const activeLane = obligation ? formatActiveLane(frame, obligation) : (frame.currentObligation?.trim() ? "this same thread" : "");
140
+ const activeLane = obligation ? formatActiveLane(frame, obligation) : "";
247
141
  const currentArtifact = formatCurrentArtifact(frame, obligation);
248
142
  const nextAction = formatNextAction(frame, obligation);
249
143
  const liveConversation = frame.currentSession
@@ -258,7 +152,7 @@ the current artifact is ${currentArtifact}.
258
152
  if i just finished or verified something concrete in this live lane, i name that as the latest checkpoint.
259
153
  the next action is ${nextAction}.
260
154
 
261
- i use those facts to answer naturally unless this turn is an explicit direct status check, where the separate exact five-line contract applies.`;
155
+ i answer naturally from those facts instead of forcing a canned status block.`;
262
156
  }
263
157
  function renderLiveThreadStatusShape(frame) {
264
158
  if (!frame.currentSession)
@@ -297,7 +191,8 @@ function buildExactStatusReply(frame, obligation, latestCheckpoint, statusCheckS
297
191
  ];
298
192
  if (statusCheckScope === "all-sessions-family") {
299
193
  lines.push("other active sessions:");
300
- lines.push(...buildOtherActiveSessionLines(frame));
194
+ const summaries = (0, active_work_1.formatOtherActiveSessionSummaries)(frame);
195
+ lines.push(...(summaries.length > 0 ? summaries : ["- none"]));
301
196
  }
302
197
  return lines.join("\n");
303
198
  }
@@ -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),
@@ -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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.105",
3
+ "version": "0.1.0-alpha.106",
4
4
  "main": "dist/heart/daemon/ouro-entry.js",
5
5
  "bin": {
6
6
  "cli": "dist/heart/daemon/ouro-bot-entry.js",