@ouro.bot/cli 0.1.0-alpha.100 → 0.1.0-alpha.101

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.101",
6
+ "changes": [
7
+ "Live coding-session status now prefers active work from the current thread instead of resurfacing stale global history, so agents stop anchoring on ancient sessions like `coding-001` when newer coding lanes are already in flight.",
8
+ "Active-work rendering and prompt steering now surface same-thread live coding lanes explicitly, giving the agent a clearer center of gravity before it answers questions about ongoing work."
9
+ ]
10
+ },
4
11
  {
5
12
  "version": "0.1.0-alpha.100",
6
13
  "changes": [
@@ -32,6 +32,20 @@ function hasSharedObligationPressure(input) {
32
32
  && input.currentObligation.trim().length > 0) || input.mustResolveBeforeHandoff
33
33
  || summarizeLiveTasks(input.taskBoard).length > 0;
34
34
  }
35
+ function formatCodingLaneLabel(session) {
36
+ return `${session.runner} ${session.id}`;
37
+ }
38
+ function describeCodingSessionScope(session, currentSession) {
39
+ if (!session.originSession)
40
+ return "";
41
+ if (currentSession
42
+ && session.originSession.friendId === currentSession.friendId
43
+ && session.originSession.channel === currentSession.channel
44
+ && session.originSession.key === currentSession.key) {
45
+ return " for this thread";
46
+ }
47
+ return ` for ${session.originSession.channel}/${session.originSession.key}`;
48
+ }
35
49
  function activeObligationCount(obligations) {
36
50
  return (obligations ?? []).filter((ob) => (0, obligations_1.isOpenObligationStatus)(ob.status)).length;
37
51
  }
@@ -106,9 +120,10 @@ function buildActiveWorkFrame(input) {
106
120
  const liveTaskNames = summarizeLiveTasks(input.taskBoard);
107
121
  const activeBridgePresent = input.bridges.some(isActiveBridge);
108
122
  const openObligations = activeObligationCount(input.pendingObligations);
123
+ const liveCodingSessions = input.codingSessions ?? [];
109
124
  const centerOfGravity = activeBridgePresent
110
125
  ? "shared-work"
111
- : (input.inner.status === "running" || input.inner.hasPending || input.mustResolveBeforeHandoff || openObligations > 0)
126
+ : (input.inner.status === "running" || input.inner.hasPending || input.mustResolveBeforeHandoff || openObligations > 0 || liveCodingSessions.length > 0)
112
127
  ? "inward-work"
113
128
  : "local-turn";
114
129
  const frame = {
@@ -127,6 +142,7 @@ function buildActiveWorkFrame(input) {
127
142
  freshestForCurrentFriend: friendSessions[0] ?? null,
128
143
  otherLiveSessionsForCurrentFriend: friendSessions,
129
144
  },
145
+ codingSessions: liveCodingSessions,
130
146
  pendingObligations: input.pendingObligations ?? [],
131
147
  targetCandidates: input.targetCandidates ?? [],
132
148
  bridgeSuggestion: suggestBridgeForActiveWork({
@@ -148,6 +164,7 @@ function buildActiveWorkFrame(input) {
148
164
  bridges: frame.bridges.length,
149
165
  liveTasks: frame.taskPressure.liveTaskNames.length,
150
166
  liveSessions: frame.friendActivity.otherLiveSessionsForCurrentFriend.length,
167
+ codingSessions: frame.codingSessions.length,
151
168
  pendingObligations: openObligations,
152
169
  hasBridgeSuggestion: frame.bridgeSuggestion !== null,
153
170
  },
@@ -205,6 +222,13 @@ function formatActiveWorkFrame(frame) {
205
222
  }
206
223
  // idle, returned, abandoned: omitted
207
224
  }
225
+ if ((frame.codingSessions ?? []).length > 0) {
226
+ lines.push("");
227
+ lines.push("## live coding work");
228
+ for (const session of frame.codingSessions) {
229
+ lines.push(`- [${session.status}] ${formatCodingLaneLabel(session)}${describeCodingSessionScope(session, frame.currentSession)}`);
230
+ }
231
+ }
208
232
  // Task pressure
209
233
  if ((frame.taskPressure?.liveTaskNames ?? []).length > 0) {
210
234
  lines.push("");
@@ -494,6 +494,23 @@ if it's separate, i can be fully present here -- my inner work will wait.`;
494
494
  i've been thinking privately and reached something.${originClause}
495
495
 
496
496
  i should bring my answer back to the conversation it came from.`;
497
+ }
498
+ const liveCodingSession = frame.codingSessions?.[0];
499
+ if (liveCodingSession) {
500
+ const sameThread = frame.currentSession
501
+ && liveCodingSession.originSession
502
+ && liveCodingSession.originSession.friendId === frame.currentSession.friendId
503
+ && liveCodingSession.originSession.channel === frame.currentSession.channel
504
+ && liveCodingSession.originSession.key === frame.currentSession.key;
505
+ const scopeClause = sameThread
506
+ ? " for this same thread"
507
+ : liveCodingSession.originSession
508
+ ? ` for ${liveCodingSession.originSession.channel}/${liveCodingSession.originSession.key}`
509
+ : "";
510
+ return `## where my attention is
511
+ i already have coding work running in ${liveCodingSession.runner} ${liveCodingSession.id}${scopeClause}.
512
+
513
+ i should orient around that live lane first, then decide what still needs to come back here.`;
497
514
  }
498
515
  return `## where my attention is
499
516
  i have unfinished work that needs attention before i move on.
@@ -60,6 +60,45 @@ function findReusableCodingSession(sessions, request) {
60
60
  const matches = sessions.filter((session) => matchesReusableCodingSession(session, request)).sort(latestSessionFirst);
61
61
  return matches[0] ?? null;
62
62
  }
63
+ function isLiveCodingStatus(status) {
64
+ return status === "spawning" || status === "running" || status === "waiting_input" || status === "stalled";
65
+ }
66
+ function rankCodingStatusSession(session, currentSession) {
67
+ return sameOriginSession({
68
+ friendId: currentSession.friendId,
69
+ channel: currentSession.channel,
70
+ key: currentSession.key,
71
+ }, session.originSession)
72
+ ? 0
73
+ : 1;
74
+ }
75
+ function selectCodingStatusSessions(sessions, currentSession) {
76
+ if (sessions.length === 0)
77
+ return [];
78
+ if (!currentSession) {
79
+ return sessions;
80
+ }
81
+ const activeSessions = sessions.filter((session) => isLiveCodingStatus(session.status)).sort(latestSessionFirst);
82
+ if (activeSessions.length > 0) {
83
+ return activeSessions.sort((left, right) => {
84
+ const rankDelta = rankCodingStatusSession(left, currentSession) - rankCodingStatusSession(right, currentSession);
85
+ if (rankDelta !== 0)
86
+ return rankDelta;
87
+ return latestSessionFirst(left, right);
88
+ });
89
+ }
90
+ const matchingClosedSessions = sessions
91
+ .filter((session) => sameOriginSession({
92
+ friendId: currentSession.friendId,
93
+ channel: currentSession.channel,
94
+ key: currentSession.key,
95
+ }, session.originSession))
96
+ .sort(latestSessionFirst);
97
+ if (matchingClosedSessions.length > 0) {
98
+ return matchingClosedSessions;
99
+ }
100
+ return [...sessions].sort(latestSessionFirst);
101
+ }
63
102
  const codingSpawnTool = {
64
103
  type: "function",
65
104
  function: {
@@ -218,12 +257,12 @@ exports.codingToolDefinitions = [
218
257
  },
219
258
  {
220
259
  tool: codingStatusTool,
221
- handler: (args) => {
260
+ handler: (args, ctx) => {
222
261
  emitCodingToolEvent("coding_status");
223
262
  const manager = (0, index_1.getCodingSessionManager)();
224
263
  const sessionId = requireArg(args, "sessionId");
225
264
  if (!sessionId) {
226
- return JSON.stringify(manager.listSessions());
265
+ return JSON.stringify(selectCodingStatusSessions(manager.listSessions(), ctx?.currentSession));
227
266
  }
228
267
  const session = manager.getSession(sessionId);
229
268
  if (!session)
@@ -11,6 +11,7 @@ const continuity_1 = require("./continuity");
11
11
  const manager_1 = require("../heart/bridges/manager");
12
12
  const identity_1 = require("../heart/identity");
13
13
  const tasks_1 = require("../repertoire/tasks");
14
+ const coding_1 = require("../repertoire/coding");
14
15
  const session_activity_1 = require("../heart/session-activity");
15
16
  const active_work_1 = require("../heart/active-work");
16
17
  const delegation_1 = require("../heart/delegation");
@@ -186,12 +187,32 @@ async function handleInboundTurn(input) {
186
187
  catch {
187
188
  pendingObligations = [];
188
189
  }
190
+ let codingSessions = [];
191
+ try {
192
+ codingSessions = (0, coding_1.getCodingSessionManager)()
193
+ .listSessions()
194
+ .filter((session) => {
195
+ if (session.status !== "spawning" && session.status !== "running" && session.status !== "waiting_input" && session.status !== "stalled") {
196
+ return false;
197
+ }
198
+ if (!session.originSession) {
199
+ return false;
200
+ }
201
+ return session.originSession.friendId === currentSession.friendId
202
+ && session.originSession.channel === currentSession.channel
203
+ && session.originSession.key === currentSession.key;
204
+ });
205
+ }
206
+ catch {
207
+ codingSessions = [];
208
+ }
189
209
  const activeWorkFrame = (0, active_work_1.buildActiveWorkFrame)({
190
210
  currentSession,
191
211
  currentObligation,
192
212
  mustResolveBeforeHandoff,
193
213
  inner: readInnerWorkState(),
194
214
  bridges: activeBridges,
215
+ codingSessions,
195
216
  pendingObligations,
196
217
  taskBoard: (() => {
197
218
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.100",
3
+ "version": "0.1.0-alpha.101",
4
4
  "main": "dist/heart/daemon/ouro-entry.js",
5
5
  "bin": {
6
6
  "cli": "dist/heart/daemon/ouro-bot-entry.js",