@ouro.bot/cli 0.1.0-alpha.13 → 0.1.0-alpha.131
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/AdoptionSpecialist.ouro/psyche/SOUL.md +2 -2
- package/AdoptionSpecialist.ouro/psyche/identities/monty.md +2 -2
- package/README.md +147 -205
- package/changelog.json +814 -0
- package/dist/heart/active-work.js +622 -0
- package/dist/heart/bridges/manager.js +358 -0
- package/dist/heart/bridges/state-machine.js +135 -0
- package/dist/heart/bridges/store.js +123 -0
- package/dist/heart/commitments.js +105 -0
- package/dist/heart/config.js +66 -21
- package/dist/heart/core.js +518 -100
- package/dist/heart/cross-chat-delivery.js +146 -0
- package/dist/heart/daemon/agent-discovery.js +81 -0
- package/dist/heart/daemon/auth-flow.js +457 -0
- package/dist/heart/daemon/daemon-cli.js +1516 -195
- package/dist/heart/daemon/daemon-entry.js +43 -2
- package/dist/heart/daemon/daemon-runtime-sync.js +212 -0
- package/dist/heart/daemon/daemon.js +261 -1
- package/dist/heart/daemon/hatch-animation.js +10 -3
- package/dist/heart/daemon/hatch-flow.js +7 -72
- package/dist/heart/daemon/hooks/bundle-meta.js +92 -0
- package/dist/heart/daemon/launchd.js +159 -0
- package/dist/heart/daemon/log-tailer.js +4 -3
- package/dist/heart/daemon/message-router.js +17 -8
- package/dist/heart/daemon/ouro-bot-global-installer.js +128 -0
- package/dist/heart/daemon/ouro-path-installer.js +57 -29
- package/dist/heart/daemon/ouro-version-manager.js +171 -0
- package/dist/heart/daemon/process-manager.js +13 -0
- package/dist/heart/daemon/run-hooks.js +37 -0
- package/dist/heart/daemon/runtime-logging.js +58 -15
- package/dist/heart/daemon/runtime-metadata.js +219 -0
- package/dist/heart/daemon/runtime-mode.js +67 -0
- package/dist/heart/daemon/sense-manager.js +50 -2
- package/dist/heart/daemon/skill-management-installer.js +94 -0
- package/dist/heart/daemon/socket-client.js +202 -0
- package/dist/heart/daemon/specialist-orchestrator.js +2 -2
- package/dist/heart/daemon/specialist-prompt.js +7 -4
- package/dist/heart/daemon/specialist-tools.js +52 -3
- package/dist/heart/daemon/staged-restart.js +114 -0
- package/dist/heart/daemon/thoughts.js +507 -0
- package/dist/heart/daemon/update-checker.js +111 -0
- package/dist/heart/daemon/update-hooks.js +138 -0
- package/dist/heart/daemon/wrapper-publish-guard.js +86 -0
- package/dist/heart/delegation.js +62 -0
- package/dist/heart/identity.js +64 -21
- package/dist/heart/kicks.js +1 -19
- package/dist/heart/model-capabilities.js +48 -0
- package/dist/heart/obligations.js +197 -0
- package/dist/heart/progress-story.js +42 -0
- package/dist/heart/provider-failover.js +88 -0
- package/dist/heart/provider-ping.js +159 -0
- package/dist/heart/providers/anthropic-token.js +163 -0
- package/dist/heart/providers/anthropic.js +195 -34
- package/dist/heart/providers/azure.js +115 -9
- package/dist/heart/providers/github-copilot.js +157 -0
- package/dist/heart/providers/minimax.js +33 -3
- package/dist/heart/providers/openai-codex.js +49 -14
- package/dist/heart/safe-workspace.js +381 -0
- package/dist/heart/session-activity.js +173 -0
- package/dist/heart/session-recall.js +216 -0
- package/dist/heart/streaming.js +108 -24
- package/dist/heart/target-resolution.js +123 -0
- package/dist/heart/tool-loop.js +194 -0
- package/dist/heart/turn-coordinator.js +28 -0
- package/dist/mind/associative-recall.js +14 -2
- package/dist/mind/bundle-manifest.js +12 -0
- package/dist/mind/context.js +60 -14
- package/dist/mind/first-impressions.js +16 -2
- package/dist/mind/friends/channel.js +35 -0
- package/dist/mind/friends/group-context.js +144 -0
- package/dist/mind/friends/store-file.js +19 -0
- package/dist/mind/friends/trust-explanation.js +74 -0
- package/dist/mind/friends/types.js +8 -0
- package/dist/mind/memory.js +27 -26
- package/dist/mind/obligation-steering.js +221 -0
- package/dist/mind/pending.js +76 -9
- package/dist/mind/phrases.js +1 -0
- package/dist/mind/prompt.js +456 -77
- package/dist/mind/token-estimate.js +8 -12
- package/dist/nerves/cli-logging.js +15 -2
- package/dist/nerves/coverage/run-artifacts.js +1 -1
- package/dist/nerves/index.js +12 -0
- package/dist/nerves/runtime.js +5 -1
- package/dist/repertoire/ado-client.js +4 -2
- package/dist/repertoire/coding/context-pack.js +254 -0
- package/dist/repertoire/coding/feedback.js +301 -0
- package/dist/repertoire/coding/index.js +4 -1
- package/dist/repertoire/coding/manager.js +210 -4
- package/dist/repertoire/coding/spawner.js +39 -9
- package/dist/repertoire/coding/tools.js +171 -4
- package/dist/repertoire/data/ado-endpoints.json +188 -0
- package/dist/repertoire/guardrails.js +290 -0
- package/dist/repertoire/mcp-client.js +254 -0
- package/dist/repertoire/mcp-manager.js +198 -0
- package/dist/repertoire/skills.js +3 -26
- package/dist/repertoire/tasks/board.js +12 -0
- package/dist/repertoire/tasks/index.js +23 -9
- package/dist/repertoire/tasks/transitions.js +1 -2
- package/dist/repertoire/tools-base.js +925 -250
- package/dist/repertoire/tools-bluebubbles.js +93 -0
- package/dist/repertoire/tools-teams.js +58 -25
- package/dist/repertoire/tools.js +106 -53
- package/dist/senses/bluebubbles-client.js +210 -5
- package/dist/senses/bluebubbles-entry.js +2 -0
- package/dist/senses/bluebubbles-inbound-log.js +109 -0
- package/dist/senses/bluebubbles-media.js +339 -0
- package/dist/senses/bluebubbles-model.js +12 -4
- package/dist/senses/bluebubbles-mutation-log.js +45 -5
- package/dist/senses/bluebubbles-runtime-state.js +109 -0
- package/dist/senses/bluebubbles-session-cleanup.js +72 -0
- package/dist/senses/bluebubbles.js +915 -45
- package/dist/senses/cli-layout.js +187 -0
- package/dist/senses/cli.js +374 -131
- package/dist/senses/continuity.js +94 -0
- package/dist/senses/debug-activity.js +154 -0
- package/dist/senses/inner-dialog-worker.js +47 -18
- package/dist/senses/inner-dialog.js +388 -83
- package/dist/senses/pipeline.js +444 -0
- package/dist/senses/teams.js +607 -129
- package/dist/senses/trust-gate.js +112 -2
- package/package.json +9 -3
- package/subagents/README.md +4 -70
- package/dist/heart/daemon/subagent-installer.js +0 -134
- package/subagents/work-doer.md +0 -233
- package/subagents/work-merger.md +0 -624
- package/subagents/work-planner.md +0 -373
|
@@ -0,0 +1,622 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatOtherActiveSessionSummaries = formatOtherActiveSessionSummaries;
|
|
4
|
+
exports.suggestBridgeForActiveWork = suggestBridgeForActiveWork;
|
|
5
|
+
exports.buildActiveWorkFrame = buildActiveWorkFrame;
|
|
6
|
+
exports.formatActiveWorkFrame = formatActiveWorkFrame;
|
|
7
|
+
exports.formatLiveWorldStateCheckpoint = formatLiveWorldStateCheckpoint;
|
|
8
|
+
const runtime_1 = require("../nerves/runtime");
|
|
9
|
+
const state_machine_1 = require("./bridges/state-machine");
|
|
10
|
+
const obligations_1 = require("./obligations");
|
|
11
|
+
const target_resolution_1 = require("./target-resolution");
|
|
12
|
+
const config_1 = require("./config");
|
|
13
|
+
const RECENT_ACTIVE_OBLIGATION_WINDOW_MS = 60 * 60 * 1000;
|
|
14
|
+
function activityPriority(source) {
|
|
15
|
+
return source === "friend-facing" ? 0 : 1;
|
|
16
|
+
}
|
|
17
|
+
function compareActivity(a, b) {
|
|
18
|
+
const sourceDiff = activityPriority(a.activitySource) - activityPriority(b.activitySource);
|
|
19
|
+
if (sourceDiff !== 0)
|
|
20
|
+
return sourceDiff;
|
|
21
|
+
return b.lastActivityMs - a.lastActivityMs;
|
|
22
|
+
}
|
|
23
|
+
function summarizeLiveTasks(taskBoard) {
|
|
24
|
+
const live = [
|
|
25
|
+
...taskBoard.byStatus.processing,
|
|
26
|
+
...taskBoard.byStatus.validating,
|
|
27
|
+
...taskBoard.byStatus.collaborating,
|
|
28
|
+
];
|
|
29
|
+
return [...new Set(live)];
|
|
30
|
+
}
|
|
31
|
+
function isActiveBridge(bridge) {
|
|
32
|
+
return bridge.lifecycle === "active";
|
|
33
|
+
}
|
|
34
|
+
function hasSharedObligationPressure(input) {
|
|
35
|
+
return input.mustResolveBeforeHandoff
|
|
36
|
+
|| summarizeLiveTasks(input.taskBoard).length > 0
|
|
37
|
+
|| activeObligationCount(input.pendingObligations) > 0;
|
|
38
|
+
}
|
|
39
|
+
function formatCodingLaneLabel(session) {
|
|
40
|
+
return `${session.runner} ${session.id}`;
|
|
41
|
+
}
|
|
42
|
+
function compactCodingCheckpoint(session) {
|
|
43
|
+
const checkpoint = session.checkpoint?.replace(/\s+/g, " ").trim();
|
|
44
|
+
if (!checkpoint)
|
|
45
|
+
return "";
|
|
46
|
+
return checkpoint.length <= 80 ? checkpoint : `${checkpoint.slice(0, 77)}...`;
|
|
47
|
+
}
|
|
48
|
+
function describeCodingSessionScope(session, currentSession) {
|
|
49
|
+
if (!session.originSession)
|
|
50
|
+
return "";
|
|
51
|
+
if (currentSession
|
|
52
|
+
&& session.originSession.friendId === currentSession.friendId
|
|
53
|
+
&& session.originSession.channel === currentSession.channel
|
|
54
|
+
&& session.originSession.key === currentSession.key) {
|
|
55
|
+
return " for this thread";
|
|
56
|
+
}
|
|
57
|
+
return ` for ${session.originSession.channel}/${session.originSession.key}`;
|
|
58
|
+
}
|
|
59
|
+
function activeObligationCount(obligations) {
|
|
60
|
+
return (obligations ?? []).filter((ob) => (0, obligations_1.isOpenObligationStatus)(ob.status)).length;
|
|
61
|
+
}
|
|
62
|
+
function obligationOriginKey(obligation) {
|
|
63
|
+
return `${obligation.origin.friendId}/${obligation.origin.channel}/${(0, config_1.sanitizeKey)(obligation.origin.key)}`;
|
|
64
|
+
}
|
|
65
|
+
function buildLiveCodingLabelSet(codingSessions, otherCodingSessions) {
|
|
66
|
+
return new Set([
|
|
67
|
+
...codingSessions.map(formatCodingLaneLabel),
|
|
68
|
+
...otherCodingSessions.map(formatCodingLaneLabel),
|
|
69
|
+
]);
|
|
70
|
+
}
|
|
71
|
+
function isMaterialActiveObligation(obligation, liveCodingLabels, nowMs) {
|
|
72
|
+
if (obligation.currentArtifact?.trim())
|
|
73
|
+
return true;
|
|
74
|
+
if (obligation.status === "waiting_for_merge" || obligation.status === "updating_runtime")
|
|
75
|
+
return true;
|
|
76
|
+
const surface = obligation.currentSurface;
|
|
77
|
+
if (surface?.kind === "merge" || surface?.kind === "runtime")
|
|
78
|
+
return true;
|
|
79
|
+
const recentlyTouched = (nowMs - obligationTimestampMs(obligation)) <= RECENT_ACTIVE_OBLIGATION_WINDOW_MS;
|
|
80
|
+
if (surface?.kind === "coding") {
|
|
81
|
+
const liveLabel = surface.label.trim();
|
|
82
|
+
return (liveLabel.length > 0 && liveCodingLabels.has(liveLabel)) || recentlyTouched;
|
|
83
|
+
}
|
|
84
|
+
return recentlyTouched;
|
|
85
|
+
}
|
|
86
|
+
function normalizePendingObligations(obligations, codingSessions, otherCodingSessions) {
|
|
87
|
+
const openObligations = (obligations ?? []).filter((obligation) => (0, obligations_1.isOpenObligationStatus)(obligation.status));
|
|
88
|
+
if (openObligations.length === 0)
|
|
89
|
+
return [];
|
|
90
|
+
const liveCodingLabels = buildLiveCodingLabelSet(codingSessions, otherCodingSessions);
|
|
91
|
+
const nowMs = Date.now();
|
|
92
|
+
const normalized = [];
|
|
93
|
+
const seenOrigins = new Set();
|
|
94
|
+
for (const obligation of [...openObligations].sort(newestObligationFirst)) {
|
|
95
|
+
if (!isMaterialActiveObligation(obligation, liveCodingLabels, nowMs))
|
|
96
|
+
continue;
|
|
97
|
+
const originKey = obligationOriginKey(obligation);
|
|
98
|
+
if (seenOrigins.has(originKey))
|
|
99
|
+
continue;
|
|
100
|
+
seenOrigins.add(originKey);
|
|
101
|
+
normalized.push(obligation);
|
|
102
|
+
}
|
|
103
|
+
return normalized;
|
|
104
|
+
}
|
|
105
|
+
function formatObligationSurface(obligation) {
|
|
106
|
+
if (!obligation.currentSurface?.label)
|
|
107
|
+
return "";
|
|
108
|
+
switch (obligation.status) {
|
|
109
|
+
case "investigating":
|
|
110
|
+
return ` (working in ${obligation.currentSurface.label})`;
|
|
111
|
+
case "waiting_for_merge":
|
|
112
|
+
return ` (waiting at ${obligation.currentSurface.label})`;
|
|
113
|
+
case "updating_runtime":
|
|
114
|
+
return ` (updating via ${obligation.currentSurface.label})`;
|
|
115
|
+
default:
|
|
116
|
+
return ` (${obligation.currentSurface.label})`;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function mergeArtifactFallback(obligation) {
|
|
120
|
+
const trimmed = obligation.content.trim();
|
|
121
|
+
if (!trimmed)
|
|
122
|
+
return "the fix";
|
|
123
|
+
const stripped = trimmed.replace(/^merge(?:\s+|$)/i, "").trim();
|
|
124
|
+
return stripped || "the fix";
|
|
125
|
+
}
|
|
126
|
+
function formatMergeArtifact(obligation) {
|
|
127
|
+
const currentArtifact = obligation.currentArtifact?.trim();
|
|
128
|
+
if (currentArtifact)
|
|
129
|
+
return currentArtifact;
|
|
130
|
+
if (obligation.currentSurface?.kind === "merge") {
|
|
131
|
+
const surfaceLabel = obligation.currentSurface.label.trim();
|
|
132
|
+
if (surfaceLabel)
|
|
133
|
+
return surfaceLabel;
|
|
134
|
+
}
|
|
135
|
+
return mergeArtifactFallback(obligation);
|
|
136
|
+
}
|
|
137
|
+
function findPrimaryOpenObligation(frame) {
|
|
138
|
+
return (frame.pendingObligations ?? []).find((ob) => ob.status !== "pending" && ob.status !== "fulfilled")
|
|
139
|
+
?? (frame.pendingObligations ?? []).find(obligations_1.isOpenObligation)
|
|
140
|
+
?? null;
|
|
141
|
+
}
|
|
142
|
+
function matchesCurrentSession(frame, obligation) {
|
|
143
|
+
return Boolean(frame.currentSession
|
|
144
|
+
&& obligation.origin.friendId === frame.currentSession.friendId
|
|
145
|
+
&& obligation.origin.channel === frame.currentSession.channel
|
|
146
|
+
&& (0, config_1.sanitizeKey)(obligation.origin.key) === (0, config_1.sanitizeKey)(frame.currentSession.key));
|
|
147
|
+
}
|
|
148
|
+
function findCurrentSessionOpenObligation(frame) {
|
|
149
|
+
return (frame.pendingObligations ?? []).find((obligation) => (0, obligations_1.isOpenObligationStatus)(obligation.status) && matchesCurrentSession(frame, obligation))
|
|
150
|
+
?? null;
|
|
151
|
+
}
|
|
152
|
+
function formatActiveLane(frame, obligation) {
|
|
153
|
+
const liveCodingSession = frame.codingSessions?.[0];
|
|
154
|
+
if (liveCodingSession) {
|
|
155
|
+
return `${formatCodingLaneLabel(liveCodingSession)}${describeCodingSessionScope(liveCodingSession, frame.currentSession)}`;
|
|
156
|
+
}
|
|
157
|
+
if (obligation?.currentSurface?.label) {
|
|
158
|
+
return obligation.currentSurface.label;
|
|
159
|
+
}
|
|
160
|
+
if (obligation && matchesCurrentSession(frame, obligation) && frame.currentSession) {
|
|
161
|
+
return "this same thread";
|
|
162
|
+
}
|
|
163
|
+
if (frame.inner?.job?.status === "running") {
|
|
164
|
+
return "inner dialog";
|
|
165
|
+
}
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
function formatCodingArtifact(session) {
|
|
169
|
+
const artifactPath = session?.artifactPath?.trim();
|
|
170
|
+
if (artifactPath)
|
|
171
|
+
return artifactPath;
|
|
172
|
+
return session ? "no PR or merge artifact yet" : null;
|
|
173
|
+
}
|
|
174
|
+
function formatCurrentArtifact(frame, obligation) {
|
|
175
|
+
if (obligation?.currentArtifact?.trim()) {
|
|
176
|
+
return obligation.currentArtifact.trim();
|
|
177
|
+
}
|
|
178
|
+
if (obligation?.currentSurface?.kind === "merge" && obligation.currentSurface.label.trim()) {
|
|
179
|
+
return obligation.currentSurface.label.trim();
|
|
180
|
+
}
|
|
181
|
+
const liveCodingArtifact = formatCodingArtifact(frame.codingSessions?.[0]);
|
|
182
|
+
if (liveCodingArtifact) {
|
|
183
|
+
return liveCodingArtifact;
|
|
184
|
+
}
|
|
185
|
+
if (obligation) {
|
|
186
|
+
return "no artifact yet";
|
|
187
|
+
}
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
function formatObligationContentNextAction(obligation) {
|
|
191
|
+
const content = obligation?.content?.trim();
|
|
192
|
+
if (!content)
|
|
193
|
+
return null;
|
|
194
|
+
return `work on "${content}" and bring back a concrete artifact`;
|
|
195
|
+
}
|
|
196
|
+
function formatNextAction(frame, obligation) {
|
|
197
|
+
const obligationHasConcreteArtifact = Boolean(obligation?.currentArtifact?.trim())
|
|
198
|
+
|| obligation?.currentSurface?.kind === "merge";
|
|
199
|
+
if (obligation?.status === "waiting_for_merge") {
|
|
200
|
+
return obligation.nextAction?.trim() || `wait for checks, merge ${formatMergeArtifact(obligation)}, then update runtime`;
|
|
201
|
+
}
|
|
202
|
+
if (obligation?.status === "updating_runtime") {
|
|
203
|
+
return obligation.nextAction?.trim() || "update runtime, verify version/changelog, then re-observe";
|
|
204
|
+
}
|
|
205
|
+
if (obligationHasConcreteArtifact && obligation?.nextAction?.trim()) {
|
|
206
|
+
return obligation.nextAction.trim();
|
|
207
|
+
}
|
|
208
|
+
const liveCodingSession = frame.codingSessions?.[0];
|
|
209
|
+
if (liveCodingSession?.status === "waiting_input") {
|
|
210
|
+
return `answer ${formatCodingLaneLabel(liveCodingSession)} and continue`;
|
|
211
|
+
}
|
|
212
|
+
if (liveCodingSession?.status === "stalled") {
|
|
213
|
+
return `unstick ${formatCodingLaneLabel(liveCodingSession)} and continue`;
|
|
214
|
+
}
|
|
215
|
+
if (liveCodingSession) {
|
|
216
|
+
return "finish the coding pass and bring the result back here";
|
|
217
|
+
}
|
|
218
|
+
if (obligation?.nextAction?.trim())
|
|
219
|
+
return obligation.nextAction.trim();
|
|
220
|
+
if (obligation) {
|
|
221
|
+
return formatObligationContentNextAction(obligation) || "continue the active loop and bring the result back here";
|
|
222
|
+
}
|
|
223
|
+
if (frame.mustResolveBeforeHandoff) {
|
|
224
|
+
return "finish what i started here before moving on";
|
|
225
|
+
}
|
|
226
|
+
return null;
|
|
227
|
+
}
|
|
228
|
+
const RECENT_OTHER_LIVE_SESSION_WINDOW_MS = 60 * 60 * 1000;
|
|
229
|
+
function sessionOriginKey(origin) {
|
|
230
|
+
return `${origin.friendId}/${origin.channel}/${(0, config_1.sanitizeKey)(origin.key)}`;
|
|
231
|
+
}
|
|
232
|
+
function codingSessionTimestampMs(session) {
|
|
233
|
+
return Date.parse(session.lastActivityAt ?? session.startedAt);
|
|
234
|
+
}
|
|
235
|
+
function obligationTimestampMs(obligation) {
|
|
236
|
+
const value = Date.parse(obligation.updatedAt ?? obligation.createdAt);
|
|
237
|
+
return Number.isFinite(value) ? value : 0;
|
|
238
|
+
}
|
|
239
|
+
function newestObligationFirst(left, right) {
|
|
240
|
+
return obligationTimestampMs(right) - obligationTimestampMs(left);
|
|
241
|
+
}
|
|
242
|
+
function formatOtherSessionArtifact(obligation, codingSession) {
|
|
243
|
+
if (obligation?.currentArtifact?.trim())
|
|
244
|
+
return obligation.currentArtifact.trim();
|
|
245
|
+
if (obligation?.currentSurface?.kind === "merge" && obligation.currentSurface.label.trim()) {
|
|
246
|
+
return obligation.currentSurface.label.trim();
|
|
247
|
+
}
|
|
248
|
+
const codingArtifact = formatCodingArtifact(codingSession);
|
|
249
|
+
if (codingArtifact)
|
|
250
|
+
return codingArtifact;
|
|
251
|
+
return obligation ? "no artifact yet" : "no explicit artifact yet";
|
|
252
|
+
}
|
|
253
|
+
function formatOtherSessionNextAction(obligation, codingSession) {
|
|
254
|
+
if (obligation?.nextAction?.trim())
|
|
255
|
+
return obligation.nextAction.trim();
|
|
256
|
+
if (obligation?.status === "waiting_for_merge") {
|
|
257
|
+
return `wait for checks, merge ${formatMergeArtifact(obligation)}, then update runtime`;
|
|
258
|
+
}
|
|
259
|
+
if (obligation?.status === "updating_runtime") {
|
|
260
|
+
return "update runtime, verify version/changelog, then re-observe";
|
|
261
|
+
}
|
|
262
|
+
if (codingSession?.status === "waiting_input") {
|
|
263
|
+
return `answer ${formatCodingLaneLabel(codingSession)} and continue`;
|
|
264
|
+
}
|
|
265
|
+
if (codingSession?.status === "stalled") {
|
|
266
|
+
return `unstick ${formatCodingLaneLabel(codingSession)} and continue`;
|
|
267
|
+
}
|
|
268
|
+
if (codingSession) {
|
|
269
|
+
return "finish the coding pass and bring the result back there";
|
|
270
|
+
}
|
|
271
|
+
if (obligation) {
|
|
272
|
+
return formatObligationContentNextAction(obligation) || "continue the active loop and bring the result back there";
|
|
273
|
+
}
|
|
274
|
+
return "check this session and bring back the latest concrete state";
|
|
275
|
+
}
|
|
276
|
+
function formatOtherSessionLine(label, status, activeLane, artifact, nextAction) {
|
|
277
|
+
return `- ${label}: [${status}] ${activeLane}; artifact ${artifact}; next ${nextAction}`;
|
|
278
|
+
}
|
|
279
|
+
function formatOtherActiveSessionSummaries(frame, nowMs = Date.now()) {
|
|
280
|
+
const originMap = new Map();
|
|
281
|
+
for (const session of frame.friendActivity?.allOtherLiveSessions ?? []) {
|
|
282
|
+
if (session.friendId === "self" || session.channel === "inner")
|
|
283
|
+
continue;
|
|
284
|
+
originMap.set(sessionOriginKey(session), {
|
|
285
|
+
friendId: session.friendId,
|
|
286
|
+
channel: session.channel,
|
|
287
|
+
key: session.key,
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
const orphanCodingSummaries = (frame.otherCodingSessions ?? [])
|
|
291
|
+
.filter((session) => !session.originSession)
|
|
292
|
+
.sort((left, right) => codingSessionTimestampMs(right) - codingSessionTimestampMs(left))
|
|
293
|
+
.map((session) => ({
|
|
294
|
+
timestampMs: codingSessionTimestampMs(session),
|
|
295
|
+
line: formatOtherSessionLine("another session", session.status, formatCodingLaneLabel(session), formatCodingArtifact(session), formatOtherSessionNextAction(null, session)),
|
|
296
|
+
}));
|
|
297
|
+
for (const session of frame.otherCodingSessions ?? []) {
|
|
298
|
+
if (!session.originSession)
|
|
299
|
+
continue;
|
|
300
|
+
if (frame.currentSession
|
|
301
|
+
&& session.originSession.friendId === frame.currentSession.friendId
|
|
302
|
+
&& session.originSession.channel === frame.currentSession.channel
|
|
303
|
+
&& (0, config_1.sanitizeKey)(session.originSession.key) === (0, config_1.sanitizeKey)(frame.currentSession.key)) {
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
originMap.set(sessionOriginKey(session.originSession), session.originSession);
|
|
307
|
+
}
|
|
308
|
+
for (const obligation of frame.pendingObligations ?? []) {
|
|
309
|
+
if (obligation.status === "fulfilled" || matchesCurrentSession(frame, obligation))
|
|
310
|
+
continue;
|
|
311
|
+
originMap.set(sessionOriginKey(obligation.origin), obligation.origin);
|
|
312
|
+
}
|
|
313
|
+
const summaries = [...originMap.values()].map((origin) => {
|
|
314
|
+
const originKey = sessionOriginKey(origin);
|
|
315
|
+
const obligation = [...(frame.pendingObligations ?? [])]
|
|
316
|
+
.filter((candidate) => candidate.status !== "fulfilled" && sessionOriginKey(candidate.origin) === originKey)
|
|
317
|
+
.sort(newestObligationFirst)[0] ?? null;
|
|
318
|
+
const codingSession = [...(frame.otherCodingSessions ?? [])]
|
|
319
|
+
.filter((candidate) => candidate.originSession && sessionOriginKey(candidate.originSession) === originKey)
|
|
320
|
+
.sort((left, right) => codingSessionTimestampMs(right) - codingSessionTimestampMs(left))[0] ?? null;
|
|
321
|
+
const liveSession = (frame.friendActivity?.allOtherLiveSessions ?? []).find((candidate) => sessionOriginKey(candidate) === originKey) ?? null;
|
|
322
|
+
const hasMaterialLiveSession = liveSession
|
|
323
|
+
? ((nowMs - liveSession.lastActivityMs) <= RECENT_OTHER_LIVE_SESSION_WINDOW_MS
|
|
324
|
+
|| (frame.currentSession != null
|
|
325
|
+
&& liveSession.friendId === frame.currentSession.friendId
|
|
326
|
+
&& liveSession.channel !== frame.currentSession.channel))
|
|
327
|
+
: false;
|
|
328
|
+
if (!obligation && !codingSession && !hasMaterialLiveSession) {
|
|
329
|
+
return null;
|
|
330
|
+
}
|
|
331
|
+
const timestampMs = Math.max(liveSession?.lastActivityMs ?? 0, codingSession ? codingSessionTimestampMs(codingSession) : 0, obligation ? obligationTimestampMs(obligation) : 0);
|
|
332
|
+
const activeLane = codingSession
|
|
333
|
+
? formatCodingLaneLabel(codingSession)
|
|
334
|
+
: obligation?.currentSurface?.label?.trim() || "this live thread";
|
|
335
|
+
const artifact = formatOtherSessionArtifact(obligation, codingSession);
|
|
336
|
+
const nextAction = formatOtherSessionNextAction(obligation, codingSession);
|
|
337
|
+
const status = obligation?.status ?? codingSession?.status ?? "active";
|
|
338
|
+
const label = liveSession?.friendName ?? origin.friendId;
|
|
339
|
+
return {
|
|
340
|
+
timestampMs,
|
|
341
|
+
line: formatOtherSessionLine(`${label}/${origin.channel}/${origin.key}`, status, activeLane, artifact, nextAction),
|
|
342
|
+
};
|
|
343
|
+
}).filter((entry) => entry !== null)
|
|
344
|
+
.sort((left, right) => right.timestampMs - left.timestampMs);
|
|
345
|
+
const lines = summaries.map((entry) => entry.line);
|
|
346
|
+
return [...lines, ...orphanCodingSummaries.map((entry) => entry.line)];
|
|
347
|
+
}
|
|
348
|
+
function suggestBridgeForActiveWork(input) {
|
|
349
|
+
const targetCandidates = (input.targetCandidates ?? [])
|
|
350
|
+
.filter((candidate) => {
|
|
351
|
+
if (candidate.delivery.mode === "blocked") {
|
|
352
|
+
return false;
|
|
353
|
+
}
|
|
354
|
+
if (candidate.activitySource !== "friend-facing" || candidate.channel === "inner") {
|
|
355
|
+
return false;
|
|
356
|
+
}
|
|
357
|
+
if (!input.currentSession) {
|
|
358
|
+
return true;
|
|
359
|
+
}
|
|
360
|
+
return !(candidate.friendId === input.currentSession.friendId
|
|
361
|
+
&& candidate.channel === input.currentSession.channel
|
|
362
|
+
&& candidate.key === input.currentSession.key);
|
|
363
|
+
})
|
|
364
|
+
.sort((a, b) => {
|
|
365
|
+
return b.lastActivityMs - a.lastActivityMs;
|
|
366
|
+
});
|
|
367
|
+
if (!hasSharedObligationPressure({
|
|
368
|
+
mustResolveBeforeHandoff: input.mustResolveBeforeHandoff,
|
|
369
|
+
taskBoard: input.taskBoard,
|
|
370
|
+
pendingObligations: input.pendingObligations,
|
|
371
|
+
}) || targetCandidates.length === 0) {
|
|
372
|
+
return null;
|
|
373
|
+
}
|
|
374
|
+
const targetSession = targetCandidates[0];
|
|
375
|
+
const objectiveHint = [...(input.pendingObligations ?? [])]
|
|
376
|
+
.find((obligation) => (0, obligations_1.isOpenObligationStatus)(obligation.status))
|
|
377
|
+
?.content?.trim() || "keep this shared work aligned";
|
|
378
|
+
const activeBridge = input.bridges.find(isActiveBridge) ?? null;
|
|
379
|
+
if (activeBridge) {
|
|
380
|
+
const alreadyAttached = activeBridge.attachedSessions.some((session) => session.friendId === targetSession.friendId
|
|
381
|
+
&& session.channel === targetSession.channel
|
|
382
|
+
&& session.key === targetSession.key);
|
|
383
|
+
if (alreadyAttached) {
|
|
384
|
+
return null;
|
|
385
|
+
}
|
|
386
|
+
return {
|
|
387
|
+
kind: "attach-existing",
|
|
388
|
+
bridgeId: activeBridge.id,
|
|
389
|
+
targetSession,
|
|
390
|
+
reason: "shared-work-candidate",
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
return {
|
|
394
|
+
kind: "begin-new",
|
|
395
|
+
targetSession,
|
|
396
|
+
objectiveHint,
|
|
397
|
+
reason: "shared-work-candidate",
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
function formatSessionLabel(session) {
|
|
401
|
+
return `${session.channel}/${session.key}`;
|
|
402
|
+
}
|
|
403
|
+
function buildActiveWorkFrame(input) {
|
|
404
|
+
const friendSessions = input.currentSession
|
|
405
|
+
? input.friendActivity
|
|
406
|
+
.filter((entry) => entry.friendId === input.currentSession?.friendId)
|
|
407
|
+
.sort(compareActivity)
|
|
408
|
+
: [];
|
|
409
|
+
const liveTaskNames = summarizeLiveTasks(input.taskBoard);
|
|
410
|
+
const activeBridgePresent = input.bridges.some(isActiveBridge);
|
|
411
|
+
const liveCodingSessions = input.codingSessions ?? [];
|
|
412
|
+
const allOtherLiveSessions = [...input.friendActivity].sort(compareActivity);
|
|
413
|
+
const otherCodingSessions = input.otherCodingSessions ?? [];
|
|
414
|
+
const pendingObligations = normalizePendingObligations(input.pendingObligations, liveCodingSessions, otherCodingSessions);
|
|
415
|
+
const openObligations = activeObligationCount(pendingObligations);
|
|
416
|
+
const centerOfGravity = activeBridgePresent
|
|
417
|
+
? "shared-work"
|
|
418
|
+
: (input.inner.status === "running" || input.inner.hasPending || input.mustResolveBeforeHandoff || openObligations > 0 || liveCodingSessions.length > 0)
|
|
419
|
+
? "inward-work"
|
|
420
|
+
: "local-turn";
|
|
421
|
+
const frame = {
|
|
422
|
+
currentSession: input.currentSession ?? null,
|
|
423
|
+
currentObligation: input.currentObligation?.trim() || null,
|
|
424
|
+
mustResolveBeforeHandoff: input.mustResolveBeforeHandoff,
|
|
425
|
+
centerOfGravity,
|
|
426
|
+
inner: input.inner,
|
|
427
|
+
bridges: input.bridges,
|
|
428
|
+
taskPressure: {
|
|
429
|
+
compactBoard: input.taskBoard.compact,
|
|
430
|
+
liveTaskNames,
|
|
431
|
+
activeBridges: input.taskBoard.activeBridges,
|
|
432
|
+
},
|
|
433
|
+
friendActivity: {
|
|
434
|
+
freshestForCurrentFriend: friendSessions[0] ?? null,
|
|
435
|
+
otherLiveSessionsForCurrentFriend: friendSessions,
|
|
436
|
+
allOtherLiveSessions,
|
|
437
|
+
},
|
|
438
|
+
codingSessions: liveCodingSessions,
|
|
439
|
+
otherCodingSessions,
|
|
440
|
+
pendingObligations,
|
|
441
|
+
targetCandidates: input.targetCandidates ?? [],
|
|
442
|
+
bridgeSuggestion: suggestBridgeForActiveWork({
|
|
443
|
+
currentSession: input.currentSession,
|
|
444
|
+
currentObligation: input.currentObligation,
|
|
445
|
+
mustResolveBeforeHandoff: input.mustResolveBeforeHandoff,
|
|
446
|
+
bridges: input.bridges,
|
|
447
|
+
pendingObligations,
|
|
448
|
+
taskBoard: input.taskBoard,
|
|
449
|
+
targetCandidates: input.targetCandidates,
|
|
450
|
+
}),
|
|
451
|
+
};
|
|
452
|
+
(0, runtime_1.emitNervesEvent)({
|
|
453
|
+
component: "engine",
|
|
454
|
+
event: "engine.active_work_build",
|
|
455
|
+
message: "built shared active-work frame",
|
|
456
|
+
meta: {
|
|
457
|
+
centerOfGravity: frame.centerOfGravity,
|
|
458
|
+
friendId: frame.currentSession?.friendId ?? null,
|
|
459
|
+
bridges: frame.bridges.length,
|
|
460
|
+
liveTasks: frame.taskPressure.liveTaskNames.length,
|
|
461
|
+
liveSessions: frame.friendActivity.otherLiveSessionsForCurrentFriend.length,
|
|
462
|
+
codingSessions: frame.codingSessions.length,
|
|
463
|
+
otherLiveSessions: allOtherLiveSessions.length,
|
|
464
|
+
otherCodingSessions: otherCodingSessions.length,
|
|
465
|
+
pendingObligations: openObligations,
|
|
466
|
+
hasBridgeSuggestion: frame.bridgeSuggestion !== null,
|
|
467
|
+
},
|
|
468
|
+
});
|
|
469
|
+
return frame;
|
|
470
|
+
}
|
|
471
|
+
function formatActiveWorkFrame(frame) {
|
|
472
|
+
const lines = ["## what i'm holding"];
|
|
473
|
+
lines.push("this is my top-level live world-state right now. inner work, coding lanes, other sessions, and return obligations all belong inside this picture.");
|
|
474
|
+
lines.push("if older checkpoints elsewhere in the transcript disagree with this picture, this picture wins.");
|
|
475
|
+
const primaryObligation = findPrimaryOpenObligation(frame);
|
|
476
|
+
const currentSessionObligation = findCurrentSessionOpenObligation(frame);
|
|
477
|
+
const activeLane = formatActiveLane(frame, primaryObligation);
|
|
478
|
+
const currentArtifact = formatCurrentArtifact(frame, primaryObligation);
|
|
479
|
+
const nextAction = formatNextAction(frame, primaryObligation);
|
|
480
|
+
const otherActiveSessions = formatOtherActiveSessionSummaries(frame);
|
|
481
|
+
// Session line
|
|
482
|
+
if (frame.currentSession) {
|
|
483
|
+
let sessionLine = `i'm in a conversation on ${formatSessionLabel(frame.currentSession)}.`;
|
|
484
|
+
if (currentSessionObligation?.content?.trim()) {
|
|
485
|
+
sessionLine += ` i still owe them: ${currentSessionObligation.content.trim()}.`;
|
|
486
|
+
}
|
|
487
|
+
else if (frame.mustResolveBeforeHandoff) {
|
|
488
|
+
sessionLine += " i need to finish what i started here before moving on.";
|
|
489
|
+
}
|
|
490
|
+
lines.push("");
|
|
491
|
+
lines.push(sessionLine);
|
|
492
|
+
}
|
|
493
|
+
else {
|
|
494
|
+
lines.push("");
|
|
495
|
+
lines.push("i'm not in a conversation right now.");
|
|
496
|
+
}
|
|
497
|
+
if (activeLane || currentArtifact || nextAction) {
|
|
498
|
+
lines.push("");
|
|
499
|
+
lines.push("## current concrete state");
|
|
500
|
+
if (frame.currentSession) {
|
|
501
|
+
lines.push(`- live conversation: ${formatSessionLabel(frame.currentSession)}`);
|
|
502
|
+
}
|
|
503
|
+
if (activeLane) {
|
|
504
|
+
lines.push(`- active lane: ${activeLane}`);
|
|
505
|
+
}
|
|
506
|
+
if (currentArtifact) {
|
|
507
|
+
lines.push(`- current artifact: ${currentArtifact}`);
|
|
508
|
+
}
|
|
509
|
+
if (nextAction) {
|
|
510
|
+
lines.push(`- next action: ${nextAction}`);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
// Inner status block
|
|
514
|
+
const job = frame.inner?.job;
|
|
515
|
+
if (job) {
|
|
516
|
+
if (job.status === "queued") {
|
|
517
|
+
let queuedLine = "i have a thought queued up for private attention.";
|
|
518
|
+
if (frame.inner?.contentSnippet) {
|
|
519
|
+
queuedLine += `\nit's about: "${frame.inner.contentSnippet}"`;
|
|
520
|
+
}
|
|
521
|
+
lines.push("");
|
|
522
|
+
lines.push(queuedLine);
|
|
523
|
+
}
|
|
524
|
+
else if (job.status === "running") {
|
|
525
|
+
const originName = job.origin?.friendName ?? job.origin?.friendId;
|
|
526
|
+
let runningLine = originName
|
|
527
|
+
? `i'm thinking through something privately right now. ${originName} asked about something and i wanted to give it real thought.`
|
|
528
|
+
: "i'm thinking through something privately right now.";
|
|
529
|
+
if (frame.inner?.obligationPending) {
|
|
530
|
+
runningLine += "\ni still owe them an answer.";
|
|
531
|
+
}
|
|
532
|
+
lines.push("");
|
|
533
|
+
lines.push(runningLine);
|
|
534
|
+
}
|
|
535
|
+
else if (job.status === "surfaced") {
|
|
536
|
+
let surfacedLine = "i finished thinking about something privately. i should bring my answer back.";
|
|
537
|
+
if (job.surfacedResult) {
|
|
538
|
+
const truncated = job.surfacedResult.length > 120 ? job.surfacedResult.slice(0, 117) + "..." : job.surfacedResult;
|
|
539
|
+
surfacedLine += `\nwhat i came to: ${truncated}`;
|
|
540
|
+
}
|
|
541
|
+
lines.push("");
|
|
542
|
+
lines.push(surfacedLine);
|
|
543
|
+
}
|
|
544
|
+
// idle, returned, abandoned: omitted
|
|
545
|
+
}
|
|
546
|
+
if ((frame.codingSessions ?? []).length > 0) {
|
|
547
|
+
lines.push("");
|
|
548
|
+
lines.push("## live coding work");
|
|
549
|
+
for (const session of frame.codingSessions) {
|
|
550
|
+
const checkpoint = compactCodingCheckpoint(session);
|
|
551
|
+
lines.push(`- [${session.status}] ${formatCodingLaneLabel(session)}${describeCodingSessionScope(session, frame.currentSession)}${checkpoint ? `: ${checkpoint}` : ""}`);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
if (otherActiveSessions.length > 0) {
|
|
555
|
+
lines.push("");
|
|
556
|
+
lines.push("## other active sessions");
|
|
557
|
+
lines.push(...otherActiveSessions);
|
|
558
|
+
}
|
|
559
|
+
// Task pressure
|
|
560
|
+
if ((frame.taskPressure?.liveTaskNames ?? []).length > 0) {
|
|
561
|
+
lines.push("");
|
|
562
|
+
lines.push(`i'm also tracking: ${frame.taskPressure.liveTaskNames.join(", ")}.`);
|
|
563
|
+
}
|
|
564
|
+
// Bridges
|
|
565
|
+
if ((frame.bridges ?? []).length > 0) {
|
|
566
|
+
const bridgeLabels = frame.bridges.map((bridge) => `${bridge.id} [${(0, state_machine_1.bridgeStateLabel)(bridge)}]`);
|
|
567
|
+
lines.push("");
|
|
568
|
+
lines.push(`i have shared work spanning sessions: ${bridgeLabels.join(", ")}.`);
|
|
569
|
+
}
|
|
570
|
+
// Target candidates (keep factual format)
|
|
571
|
+
const targetCandidatesBlock = frame.targetCandidates && frame.targetCandidates.length > 0
|
|
572
|
+
? (0, target_resolution_1.formatTargetSessionCandidates)(frame.targetCandidates)
|
|
573
|
+
: "";
|
|
574
|
+
if (targetCandidatesBlock) {
|
|
575
|
+
lines.push("");
|
|
576
|
+
lines.push(targetCandidatesBlock);
|
|
577
|
+
}
|
|
578
|
+
if ((frame.pendingObligations ?? []).length > 0) {
|
|
579
|
+
lines.push("");
|
|
580
|
+
lines.push("## return obligations");
|
|
581
|
+
for (const obligation of frame.pendingObligations) {
|
|
582
|
+
if (!(0, obligations_1.isOpenObligationStatus)(obligation.status))
|
|
583
|
+
continue;
|
|
584
|
+
let obligationLine = `- [${obligation.status}] ${obligation.origin.friendId}/${obligation.origin.channel}/${obligation.origin.key}: ${obligation.content}${formatObligationSurface(obligation)}`;
|
|
585
|
+
if (obligation.latestNote?.trim()) {
|
|
586
|
+
obligationLine += `\n latest: ${obligation.latestNote.trim()}`;
|
|
587
|
+
}
|
|
588
|
+
lines.push(obligationLine);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
// Bridge suggestion
|
|
592
|
+
if (frame.bridgeSuggestion) {
|
|
593
|
+
lines.push("");
|
|
594
|
+
if (frame.bridgeSuggestion.kind === "begin-new") {
|
|
595
|
+
lines.push(`this work touches my conversation on ${formatSessionLabel(frame.bridgeSuggestion.targetSession)} too -- i should connect these threads.`);
|
|
596
|
+
}
|
|
597
|
+
else {
|
|
598
|
+
lines.push(`this work relates to bridge ${frame.bridgeSuggestion.bridgeId} -- i should connect ${formatSessionLabel(frame.bridgeSuggestion.targetSession)} to it.`);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
return lines.join("\n");
|
|
602
|
+
}
|
|
603
|
+
function formatLiveWorldStateCheckpoint(frame) {
|
|
604
|
+
const primaryObligation = findPrimaryOpenObligation(frame);
|
|
605
|
+
const activeLane = formatActiveLane(frame, primaryObligation) ?? "no explicit live lane";
|
|
606
|
+
const currentArtifact = formatCurrentArtifact(frame, primaryObligation) ?? "no artifact yet";
|
|
607
|
+
const nextAction = formatNextAction(frame, primaryObligation) ?? "continue from the live world-state";
|
|
608
|
+
const otherActiveSessions = formatOtherActiveSessionSummaries(frame);
|
|
609
|
+
const lines = [
|
|
610
|
+
"## live world-state checkpoint",
|
|
611
|
+
"this is the freshest reality for this turn. if older transcript history disagrees, treat it as stale.",
|
|
612
|
+
`- live conversation: ${frame.currentSession ? formatSessionLabel(frame.currentSession) : "not in a live conversation"}`,
|
|
613
|
+
`- active lane: ${activeLane}`,
|
|
614
|
+
`- current artifact: ${currentArtifact}`,
|
|
615
|
+
`- next action: ${nextAction}`,
|
|
616
|
+
];
|
|
617
|
+
if (otherActiveSessions.length > 0) {
|
|
618
|
+
lines.push("other active sessions:");
|
|
619
|
+
lines.push(...otherActiveSessions);
|
|
620
|
+
}
|
|
621
|
+
return lines.join("\n");
|
|
622
|
+
}
|