@ouro.bot/cli 0.1.0-alpha.101 → 0.1.0-alpha.102
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.102",
|
|
6
|
+
"changes": [
|
|
7
|
+
"Live obligations now persist a concrete current artifact and next action, so status answers can anchor on the actual active lane, artifact, and immediate step instead of drifting into broad mission statements.",
|
|
8
|
+
"Obligation-bound coding feedback now turns PR milestones into structured report-backs and lifecycle updates, which keeps the originating live conversation informed when child work opens a PR, waits for merge, or needs a runtime update."
|
|
9
|
+
]
|
|
10
|
+
},
|
|
4
11
|
{
|
|
5
12
|
"version": "0.1.0-alpha.101",
|
|
6
13
|
"changes": [
|
|
@@ -63,6 +63,62 @@ function formatObligationSurface(obligation) {
|
|
|
63
63
|
return ` (${obligation.currentSurface.label})`;
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
|
+
function findPrimaryOpenObligation(frame) {
|
|
67
|
+
return (frame.pendingObligations ?? []).find((ob) => ob.status !== "pending" && ob.status !== "fulfilled")
|
|
68
|
+
?? (frame.pendingObligations ?? []).find(obligations_1.isOpenObligation)
|
|
69
|
+
?? null;
|
|
70
|
+
}
|
|
71
|
+
function formatActiveLane(frame, obligation) {
|
|
72
|
+
const liveCodingSession = frame.codingSessions?.[0];
|
|
73
|
+
if (liveCodingSession) {
|
|
74
|
+
return `${formatCodingLaneLabel(liveCodingSession)}${describeCodingSessionScope(liveCodingSession, frame.currentSession)}`;
|
|
75
|
+
}
|
|
76
|
+
if (obligation?.currentSurface?.label) {
|
|
77
|
+
return obligation.currentSurface.label;
|
|
78
|
+
}
|
|
79
|
+
if (frame.inner?.job?.status === "running") {
|
|
80
|
+
return "inner dialog";
|
|
81
|
+
}
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
function formatCurrentArtifact(frame, obligation) {
|
|
85
|
+
if (obligation?.currentArtifact?.trim()) {
|
|
86
|
+
return obligation.currentArtifact.trim();
|
|
87
|
+
}
|
|
88
|
+
if (obligation?.currentSurface?.kind === "merge" && obligation.currentSurface.label.trim()) {
|
|
89
|
+
return obligation.currentSurface.label.trim();
|
|
90
|
+
}
|
|
91
|
+
if ((frame.codingSessions ?? []).length > 0) {
|
|
92
|
+
return "no PR or merge artifact yet";
|
|
93
|
+
}
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
function formatNextAction(frame, obligation) {
|
|
97
|
+
if (obligation?.nextAction?.trim()) {
|
|
98
|
+
return obligation.nextAction.trim();
|
|
99
|
+
}
|
|
100
|
+
const liveCodingSession = frame.codingSessions?.[0];
|
|
101
|
+
if (liveCodingSession?.status === "waiting_input") {
|
|
102
|
+
return `answer ${formatCodingLaneLabel(liveCodingSession)} and continue`;
|
|
103
|
+
}
|
|
104
|
+
if (liveCodingSession?.status === "stalled") {
|
|
105
|
+
return `unstick ${formatCodingLaneLabel(liveCodingSession)} and continue`;
|
|
106
|
+
}
|
|
107
|
+
if (liveCodingSession) {
|
|
108
|
+
return "finish the coding pass and bring the result back here";
|
|
109
|
+
}
|
|
110
|
+
if (obligation?.status === "waiting_for_merge") {
|
|
111
|
+
const artifact = formatCurrentArtifact(frame, obligation) ?? "the fix";
|
|
112
|
+
return `wait for checks, merge ${artifact}, then update runtime`;
|
|
113
|
+
}
|
|
114
|
+
if (obligation?.status === "updating_runtime") {
|
|
115
|
+
return "update runtime, verify version/changelog, then re-observe";
|
|
116
|
+
}
|
|
117
|
+
if (obligation) {
|
|
118
|
+
return "continue the active loop and bring the result back here";
|
|
119
|
+
}
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
66
122
|
function suggestBridgeForActiveWork(input) {
|
|
67
123
|
const targetCandidates = (input.targetCandidates ?? [])
|
|
68
124
|
.filter((candidate) => {
|
|
@@ -173,6 +229,10 @@ function buildActiveWorkFrame(input) {
|
|
|
173
229
|
}
|
|
174
230
|
function formatActiveWorkFrame(frame) {
|
|
175
231
|
const lines = ["## what i'm holding"];
|
|
232
|
+
const primaryObligation = findPrimaryOpenObligation(frame);
|
|
233
|
+
const activeLane = formatActiveLane(frame, primaryObligation);
|
|
234
|
+
const currentArtifact = formatCurrentArtifact(frame, primaryObligation);
|
|
235
|
+
const nextAction = formatNextAction(frame, primaryObligation);
|
|
176
236
|
// Session line
|
|
177
237
|
if (frame.currentSession) {
|
|
178
238
|
let sessionLine = `i'm in a conversation on ${formatSessionLabel(frame.currentSession)}.`;
|
|
@@ -189,6 +249,22 @@ function formatActiveWorkFrame(frame) {
|
|
|
189
249
|
lines.push("");
|
|
190
250
|
lines.push("i'm not in a conversation right now.");
|
|
191
251
|
}
|
|
252
|
+
if (activeLane || currentArtifact || nextAction) {
|
|
253
|
+
lines.push("");
|
|
254
|
+
lines.push("## current concrete state");
|
|
255
|
+
if (frame.currentSession) {
|
|
256
|
+
lines.push(`- live conversation: ${formatSessionLabel(frame.currentSession)}`);
|
|
257
|
+
}
|
|
258
|
+
if (activeLane) {
|
|
259
|
+
lines.push(`- active lane: ${activeLane}`);
|
|
260
|
+
}
|
|
261
|
+
if (currentArtifact) {
|
|
262
|
+
lines.push(`- current artifact: ${currentArtifact}`);
|
|
263
|
+
}
|
|
264
|
+
if (nextAction) {
|
|
265
|
+
lines.push(`- next action: ${nextAction}`);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
192
268
|
// Inner status block
|
|
193
269
|
const job = frame.inner?.job;
|
|
194
270
|
if (job) {
|
|
@@ -140,6 +140,12 @@ function advanceObligation(agentRoot, obligationId, update) {
|
|
|
140
140
|
if (update.currentSurface) {
|
|
141
141
|
obligation.currentSurface = update.currentSurface;
|
|
142
142
|
}
|
|
143
|
+
if (typeof update.currentArtifact === "string") {
|
|
144
|
+
obligation.currentArtifact = update.currentArtifact;
|
|
145
|
+
}
|
|
146
|
+
if (typeof update.nextAction === "string") {
|
|
147
|
+
obligation.nextAction = update.nextAction;
|
|
148
|
+
}
|
|
143
149
|
if (typeof update.latestNote === "string") {
|
|
144
150
|
obligation.latestNote = update.latestNote;
|
|
145
151
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.findActivePersistentObligation = findActivePersistentObligation;
|
|
4
4
|
exports.renderActiveObligationSteering = renderActiveObligationSteering;
|
|
5
|
+
exports.renderConcreteStatusGuidance = renderConcreteStatusGuidance;
|
|
5
6
|
const runtime_1 = require("../nerves/runtime");
|
|
6
7
|
function findActivePersistentObligation(frame) {
|
|
7
8
|
if (!frame)
|
|
@@ -29,3 +30,58 @@ i'm already working on something i owe ${name}.${surfaceLine}
|
|
|
29
30
|
|
|
30
31
|
i should close that loop before i act like this is a fresh blank turn.`;
|
|
31
32
|
}
|
|
33
|
+
function formatActiveLane(frame, obligation) {
|
|
34
|
+
const liveCodingSession = frame.codingSessions?.[0];
|
|
35
|
+
if (liveCodingSession) {
|
|
36
|
+
const sameThread = frame.currentSession
|
|
37
|
+
&& liveCodingSession.originSession
|
|
38
|
+
&& liveCodingSession.originSession.friendId === frame.currentSession.friendId
|
|
39
|
+
&& liveCodingSession.originSession.channel === frame.currentSession.channel
|
|
40
|
+
&& liveCodingSession.originSession.key === frame.currentSession.key;
|
|
41
|
+
return sameThread
|
|
42
|
+
? `${liveCodingSession.runner} ${liveCodingSession.id} for this same thread`
|
|
43
|
+
: liveCodingSession.originSession
|
|
44
|
+
? `${liveCodingSession.runner} ${liveCodingSession.id} for ${liveCodingSession.originSession.channel}/${liveCodingSession.originSession.key}`
|
|
45
|
+
: `${liveCodingSession.runner} ${liveCodingSession.id}`;
|
|
46
|
+
}
|
|
47
|
+
return obligation.currentSurface?.label || "this live loop";
|
|
48
|
+
}
|
|
49
|
+
function formatCurrentArtifact(frame, obligation) {
|
|
50
|
+
return obligation.currentArtifact
|
|
51
|
+
|| (obligation.currentSurface?.kind === "merge" ? obligation.currentSurface.label : "")
|
|
52
|
+
|| ((frame.codingSessions ?? []).length > 0 ? "no PR or merge artifact yet" : "no explicit artifact yet");
|
|
53
|
+
}
|
|
54
|
+
function formatNextAction(frame, obligation) {
|
|
55
|
+
if (obligation.nextAction)
|
|
56
|
+
return obligation.nextAction;
|
|
57
|
+
const liveCodingSession = frame.codingSessions?.[0];
|
|
58
|
+
if (liveCodingSession?.status === "waiting_input") {
|
|
59
|
+
return `answer ${liveCodingSession.runner} ${liveCodingSession.id} and continue`;
|
|
60
|
+
}
|
|
61
|
+
if (liveCodingSession?.status === "stalled") {
|
|
62
|
+
return `unstick ${liveCodingSession.runner} ${liveCodingSession.id} and continue`;
|
|
63
|
+
}
|
|
64
|
+
if (liveCodingSession) {
|
|
65
|
+
return "finish the coding pass and bring the result back here";
|
|
66
|
+
}
|
|
67
|
+
if (obligation.status === "waiting_for_merge") {
|
|
68
|
+
return `wait for checks, merge ${formatCurrentArtifact(frame, obligation)}, then update runtime`;
|
|
69
|
+
}
|
|
70
|
+
if (obligation.status === "updating_runtime") {
|
|
71
|
+
return "update runtime, verify version/changelog, then re-observe";
|
|
72
|
+
}
|
|
73
|
+
return "continue the active loop and bring the result back here";
|
|
74
|
+
}
|
|
75
|
+
function renderConcreteStatusGuidance(frame, obligation) {
|
|
76
|
+
if (!obligation)
|
|
77
|
+
return "";
|
|
78
|
+
const activeLane = formatActiveLane(frame, obligation);
|
|
79
|
+
const currentArtifact = formatCurrentArtifact(frame, obligation);
|
|
80
|
+
const nextAction = formatNextAction(frame, obligation);
|
|
81
|
+
return `if someone asks what i'm doing or for status, i answer from the concrete state:
|
|
82
|
+
- active lane: ${activeLane}
|
|
83
|
+
- current artifact: ${currentArtifact}
|
|
84
|
+
- next action: ${nextAction}
|
|
85
|
+
|
|
86
|
+
i don't replace that with a broad mission statement if this concrete state is available.`;
|
|
87
|
+
}
|
package/dist/mind/prompt.js
CHANGED
|
@@ -470,7 +470,9 @@ function centerOfGravitySteeringSection(channel, options) {
|
|
|
470
470
|
const activeObligation = (0, obligation_steering_1.findActivePersistentObligation)(frame);
|
|
471
471
|
if (cog === "inward-work") {
|
|
472
472
|
if (activeObligation) {
|
|
473
|
-
return (0, obligation_steering_1.renderActiveObligationSteering)(activeObligation)
|
|
473
|
+
return `${(0, obligation_steering_1.renderActiveObligationSteering)(activeObligation)}
|
|
474
|
+
|
|
475
|
+
${(0, obligation_steering_1.renderConcreteStatusGuidance)(frame, activeObligation)}`;
|
|
474
476
|
}
|
|
475
477
|
if (job?.status === "queued" || job?.status === "running") {
|
|
476
478
|
const originClause = job.origin
|
|
@@ -14,6 +14,8 @@ const OBLIGATION_WAKE_UPDATE_KINDS = new Set([
|
|
|
14
14
|
"failed",
|
|
15
15
|
"killed",
|
|
16
16
|
]);
|
|
17
|
+
const PULL_REQUEST_NUMBER_PATTERN = /\bPR\s*#(\d+)\b/i;
|
|
18
|
+
const PULL_REQUEST_URL_PATTERN = /\/pull\/(\d+)(?:\b|\/)?/i;
|
|
17
19
|
function clip(text, maxLength = 280) {
|
|
18
20
|
const trimmed = text.trim();
|
|
19
21
|
if (trimmed.length <= maxLength)
|
|
@@ -57,6 +59,61 @@ function formatSessionLabel(session) {
|
|
|
57
59
|
: "";
|
|
58
60
|
return `${session.runner} ${session.id}${origin}`;
|
|
59
61
|
}
|
|
62
|
+
function extractPullRequestLabel(snippet) {
|
|
63
|
+
if (!snippet)
|
|
64
|
+
return null;
|
|
65
|
+
const numberMatch = snippet.match(PULL_REQUEST_NUMBER_PATTERN);
|
|
66
|
+
if (numberMatch)
|
|
67
|
+
return `PR #${numberMatch[1]}`;
|
|
68
|
+
const urlMatch = snippet.match(PULL_REQUEST_URL_PATTERN);
|
|
69
|
+
if (urlMatch)
|
|
70
|
+
return `PR #${urlMatch[1]}`;
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
function isMergedPullRequestSnippet(snippet) {
|
|
74
|
+
return /\bmerged\b/i.test(snippet) || /\blanded\b/i.test(snippet);
|
|
75
|
+
}
|
|
76
|
+
function deriveObligationMilestone(update) {
|
|
77
|
+
const snippet = pickUpdateSnippet(update);
|
|
78
|
+
const pullRequest = extractPullRequestLabel(snippet);
|
|
79
|
+
if (update.kind === "completed" && snippet && pullRequest && isMergedPullRequestSnippet(snippet)) {
|
|
80
|
+
return {
|
|
81
|
+
status: "updating_runtime",
|
|
82
|
+
currentSurface: { kind: "runtime", label: "ouro up" },
|
|
83
|
+
currentArtifact: pullRequest,
|
|
84
|
+
nextAction: "update runtime, verify version/changelog, then re-observe",
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
if (update.kind === "completed" && pullRequest) {
|
|
88
|
+
return {
|
|
89
|
+
status: "waiting_for_merge",
|
|
90
|
+
currentSurface: { kind: "merge", label: pullRequest },
|
|
91
|
+
currentArtifact: pullRequest,
|
|
92
|
+
nextAction: `wait for checks, merge ${pullRequest}, then update runtime`,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
if (update.kind === "waiting_input") {
|
|
96
|
+
return {
|
|
97
|
+
status: "investigating",
|
|
98
|
+
currentSurface: { kind: "coding", label: `${update.session.runner} ${update.session.id}` },
|
|
99
|
+
nextAction: `answer ${update.session.runner} ${update.session.id} and continue`,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
if (update.kind === "stalled") {
|
|
103
|
+
return {
|
|
104
|
+
status: "investigating",
|
|
105
|
+
currentSurface: { kind: "coding", label: `${update.session.runner} ${update.session.id}` },
|
|
106
|
+
nextAction: `unstick ${update.session.runner} ${update.session.id} and continue`,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
if (update.kind === "progress" || update.kind === "spawned" || update.kind === "failed" || update.kind === "killed" || update.kind === "completed") {
|
|
110
|
+
return {
|
|
111
|
+
status: "investigating",
|
|
112
|
+
currentSurface: { kind: "coding", label: `${update.session.runner} ${update.session.id}` },
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
60
117
|
function isSafeProgressSnippet(snippet) {
|
|
61
118
|
const wordCount = snippet.split(/\s+/).filter(Boolean).length;
|
|
62
119
|
return (snippet.length <= 80
|
|
@@ -94,6 +151,22 @@ function formatUpdateMessage(update) {
|
|
|
94
151
|
return `${label} started`;
|
|
95
152
|
}
|
|
96
153
|
}
|
|
154
|
+
function formatReportBackMessage(update, baseMessage) {
|
|
155
|
+
if (!baseMessage)
|
|
156
|
+
return null;
|
|
157
|
+
if (!update.session.obligationId || !update.session.originSession) {
|
|
158
|
+
return baseMessage;
|
|
159
|
+
}
|
|
160
|
+
const milestone = deriveObligationMilestone(update);
|
|
161
|
+
const extraLines = [];
|
|
162
|
+
if (milestone?.currentArtifact) {
|
|
163
|
+
extraLines.push(`current artifact: ${milestone.currentArtifact}`);
|
|
164
|
+
}
|
|
165
|
+
if (milestone?.nextAction) {
|
|
166
|
+
extraLines.push(`next: ${milestone.nextAction}`);
|
|
167
|
+
}
|
|
168
|
+
return extraLines.length > 0 ? `${baseMessage}\n${extraLines.join("\n")}` : baseMessage;
|
|
169
|
+
}
|
|
97
170
|
function obligationNoteFromUpdate(update) {
|
|
98
171
|
const snippet = pickUpdateSnippet(update);
|
|
99
172
|
switch (update.kind) {
|
|
@@ -121,10 +194,13 @@ function syncObligationFromUpdate(update) {
|
|
|
121
194
|
const obligationId = update.session.obligationId;
|
|
122
195
|
if (!obligationId)
|
|
123
196
|
return;
|
|
197
|
+
const milestone = deriveObligationMilestone(update);
|
|
124
198
|
try {
|
|
125
199
|
(0, obligations_1.advanceObligation)((0, identity_1.getAgentRoot)(), obligationId, {
|
|
126
|
-
status: "investigating",
|
|
127
|
-
currentSurface: { kind: "coding", label: `${update.session.runner} ${update.session.id}` },
|
|
200
|
+
status: milestone?.status ?? "investigating",
|
|
201
|
+
currentSurface: milestone?.currentSurface ?? { kind: "coding", label: `${update.session.runner} ${update.session.id}` },
|
|
202
|
+
currentArtifact: milestone?.currentArtifact,
|
|
203
|
+
nextAction: milestone?.nextAction,
|
|
128
204
|
latestNote: obligationNoteFromUpdate(update) ?? undefined,
|
|
129
205
|
});
|
|
130
206
|
}
|
|
@@ -193,10 +269,10 @@ function attachCodingSessionFeedback(manager, session, target) {
|
|
|
193
269
|
};
|
|
194
270
|
const spawnedUpdate = { kind: "spawned", session };
|
|
195
271
|
syncObligationFromUpdate(spawnedUpdate);
|
|
196
|
-
sendMessage(formatUpdateMessage(spawnedUpdate));
|
|
272
|
+
sendMessage(formatReportBackMessage(spawnedUpdate, formatUpdateMessage(spawnedUpdate)));
|
|
197
273
|
unsubscribe = manager.subscribe(session.id, async (update) => {
|
|
198
274
|
syncObligationFromUpdate(update);
|
|
199
|
-
sendMessage(formatUpdateMessage(update));
|
|
275
|
+
sendMessage(formatReportBackMessage(update, formatUpdateMessage(update)));
|
|
200
276
|
await wakeInnerDialogForObligation(update);
|
|
201
277
|
if (TERMINAL_UPDATE_KINDS.has(update.kind)) {
|
|
202
278
|
closed = true;
|