@ouro.bot/cli 0.1.0-alpha.280 → 0.1.0-alpha.281
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.281",
|
|
6
|
+
"changes": [
|
|
7
|
+
"feat(bundle): new `src/heart/bundle-state.ts` module exports `detectBundleState(agentRoot)` which returns a structured `BundleStateIssue[]` describing git-level problems the agent can remediate. Enum cases: `not_a_git_repo`, `no_remote_configured`, `first_commit_never_happened`, `pending_sync_exists`. Detection never throws — every git call is wrapped in try/catch so a broken bundle degrades to a clear signal rather than crashing the turn pipeline. Also exports `renderBundleStateHint(issues)` which produces first-person remediation guidance (per the memory rule) that tells the agent to call `bundle_check_sync_status` and the `bundle_*` tools shipping in a follow-up PR.",
|
|
8
|
+
"feat(bundle): `StartOfTurnPacket` gains an optional `bundleState?: BundleStateIssue[]` field, populated by the senses pipeline in `handleInboundTurn` at packet assembly time. Renders via a new `case \"bundleState\":` branch in `formatSections` with the `**Bundle:**` prefix, at the same priority tier as the legacy `syncFailure` free-form string (priority 7, truncated last). The two signals coexist during the transition — `syncFailure` is still emitted by sync.ts for humans, while `bundleState` is the structured form the agent pattern-matches on. Deferred to follow-up: `pending-sync.json` schema extension with `classification` / `conflictFiles` so sync.ts can distinguish push-rejected from pull-rebase-conflict."
|
|
9
|
+
]
|
|
10
|
+
},
|
|
4
11
|
{
|
|
5
12
|
"version": "0.1.0-alpha.280",
|
|
6
13
|
"changes": [
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.detectBundleState = detectBundleState;
|
|
37
|
+
exports.renderBundleStateHint = renderBundleStateHint;
|
|
38
|
+
/**
|
|
39
|
+
* Bundle state detection: inspects an agent bundle's git + pending-sync
|
|
40
|
+
* state and returns a structured list of issues the agent needs to remediate
|
|
41
|
+
* via its `bundle_*` tools.
|
|
42
|
+
*
|
|
43
|
+
* Previously the sync pipeline surfaced a single free-form `syncFailure`
|
|
44
|
+
* string that was good for humans but hard for the agent to act on. The
|
|
45
|
+
* new `BundleStateIssue` enum lets the agent pattern-match on discrete
|
|
46
|
+
* cases and pick the correct remediation tool (shipping in PR 6).
|
|
47
|
+
*
|
|
48
|
+
* Detection never throws: every git call is wrapped in try/catch so a
|
|
49
|
+
* broken bundle or a missing git binary degrades to an empty array or a
|
|
50
|
+
* `not_a_git_repo` signal rather than exploding the turn pipeline.
|
|
51
|
+
*
|
|
52
|
+
* The classification returned here is the subset that's detectable purely
|
|
53
|
+
* from bundle state:
|
|
54
|
+
*
|
|
55
|
+
* - `not_a_git_repo`: `.git` directory missing.
|
|
56
|
+
* - `no_remote_configured`: `git remote` returns empty.
|
|
57
|
+
* - `first_commit_never_happened`: `.git` exists but `git rev-parse HEAD`
|
|
58
|
+
* fails (fresh `git init` with nothing committed).
|
|
59
|
+
* - `pending_sync_exists`: `state/pending-sync.json` exists — the agent
|
|
60
|
+
* should inspect it and clear the pending state.
|
|
61
|
+
*
|
|
62
|
+
* Future extensions (deferred to a follow-up PR):
|
|
63
|
+
* - `remote_push_failed` / `pull_rebase_conflict`: derived from the
|
|
64
|
+
* `classification` field of pending-sync.json once sync.ts writes it.
|
|
65
|
+
*/
|
|
66
|
+
const child_process_1 = require("child_process");
|
|
67
|
+
const fs = __importStar(require("fs"));
|
|
68
|
+
const path = __importStar(require("path"));
|
|
69
|
+
const runtime_1 = require("../nerves/runtime");
|
|
70
|
+
function detectBundleState(agentRoot, deps = {}) {
|
|
71
|
+
const exec = deps.execFileSync ?? child_process_1.execFileSync;
|
|
72
|
+
const exists = deps.existsSync ?? fs.existsSync;
|
|
73
|
+
const issues = [];
|
|
74
|
+
(0, runtime_1.emitNervesEvent)({
|
|
75
|
+
component: "heart",
|
|
76
|
+
event: "heart.bundle_state_detect_start",
|
|
77
|
+
message: "detecting bundle state",
|
|
78
|
+
meta: { agentRoot },
|
|
79
|
+
});
|
|
80
|
+
const gitDir = path.join(agentRoot, ".git");
|
|
81
|
+
const isGitRepo = exists(gitDir);
|
|
82
|
+
if (!isGitRepo) {
|
|
83
|
+
issues.push("not_a_git_repo");
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
// Check remote presence
|
|
87
|
+
try {
|
|
88
|
+
const remoteOutput = exec("git", ["remote"], {
|
|
89
|
+
cwd: agentRoot,
|
|
90
|
+
stdio: "pipe",
|
|
91
|
+
timeout: 5000,
|
|
92
|
+
}).toString().trim();
|
|
93
|
+
if (remoteOutput.length === 0) {
|
|
94
|
+
issues.push("no_remote_configured");
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
// Git missing or broken — treat as no_remote_configured so the
|
|
99
|
+
// agent surfaces a "fix git" signal rather than a silent pass.
|
|
100
|
+
issues.push("no_remote_configured");
|
|
101
|
+
}
|
|
102
|
+
// Check for initial commit
|
|
103
|
+
try {
|
|
104
|
+
exec("git", ["rev-parse", "HEAD"], {
|
|
105
|
+
cwd: agentRoot,
|
|
106
|
+
stdio: "pipe",
|
|
107
|
+
timeout: 5000,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
issues.push("first_commit_never_happened");
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// Pending-sync file — independent of git state (could exist on a bundle
|
|
115
|
+
// that was a repo and then had its .git deleted).
|
|
116
|
+
const pendingSyncPath = path.join(agentRoot, "state", "pending-sync.json");
|
|
117
|
+
if (exists(pendingSyncPath)) {
|
|
118
|
+
issues.push("pending_sync_exists");
|
|
119
|
+
}
|
|
120
|
+
(0, runtime_1.emitNervesEvent)({
|
|
121
|
+
component: "heart",
|
|
122
|
+
event: "heart.bundle_state_detect_end",
|
|
123
|
+
message: `bundle state detected: ${issues.length} issue(s)`,
|
|
124
|
+
meta: { agentRoot, issues },
|
|
125
|
+
});
|
|
126
|
+
return issues;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* First-person remediation hint text for the start-of-turn packet. Reads
|
|
130
|
+
* as the agent's own voice per the "declarative first-person" memory rule.
|
|
131
|
+
* Returns empty string when there are no issues (so the packet renderer
|
|
132
|
+
* can skip the section entirely).
|
|
133
|
+
*/
|
|
134
|
+
function renderBundleStateHint(issues) {
|
|
135
|
+
if (issues.length === 0)
|
|
136
|
+
return "";
|
|
137
|
+
const labels = {
|
|
138
|
+
not_a_git_repo: "not a git repo",
|
|
139
|
+
no_remote_configured: "no remote configured",
|
|
140
|
+
first_commit_never_happened: "first commit never happened",
|
|
141
|
+
pending_sync_exists: "pending sync from a prior turn",
|
|
142
|
+
};
|
|
143
|
+
const list = issues.map((issue) => labels[issue]).join(", ");
|
|
144
|
+
return (`my bundle has unresolved git state: ${list}. ` +
|
|
145
|
+
`i have the bundle_* tools available to fix this — i should run ` +
|
|
146
|
+
`bundle_check_sync_status first, then use the appropriate remediation tool.`);
|
|
147
|
+
}
|
|
@@ -40,6 +40,7 @@ exports.renderCompactStartOfTurnPacket = renderCompactStartOfTurnPacket;
|
|
|
40
40
|
const fs = __importStar(require("fs"));
|
|
41
41
|
const path = __importStar(require("path"));
|
|
42
42
|
const runtime_1 = require("../nerves/runtime");
|
|
43
|
+
const bundle_state_1 = require("./bundle-state");
|
|
43
44
|
const tempo_1 = require("./tempo");
|
|
44
45
|
function estimateTokens(text) {
|
|
45
46
|
return Math.ceil(text.length / 4);
|
|
@@ -222,6 +223,11 @@ function renderStartOfTurnPacket(packet) {
|
|
|
222
223
|
// Assemble sections in priority order (highest priority first for budget allocation)
|
|
223
224
|
// Each section is { label, content, priority } where lower priority number = truncated first
|
|
224
225
|
const sections = [
|
|
226
|
+
// bundleState and syncFailure share the top remediation tier — both
|
|
227
|
+
// are actionable "fix your git" signals. bundleState is preferred
|
|
228
|
+
// because it's structured (array of enum values) while syncFailure is
|
|
229
|
+
// a legacy free-form string; both render when populated.
|
|
230
|
+
{ label: "bundleState", content: (0, bundle_state_1.renderBundleStateHint)(packet.bundleState ?? []), priority: 7 },
|
|
225
231
|
{ label: "syncFailure", content: packet.syncFailure ?? "", priority: 7 },
|
|
226
232
|
{ label: "resume", content: packet.resumeHint, priority: 6 },
|
|
227
233
|
{ label: "obligations", content: packet.obligations, priority: 5 },
|
|
@@ -294,6 +300,9 @@ function formatSections(sections) {
|
|
|
294
300
|
case "syncFailure":
|
|
295
301
|
parts.push(`**Sync warning:** ${section.content}`);
|
|
296
302
|
break;
|
|
303
|
+
case "bundleState":
|
|
304
|
+
parts.push(`**Bundle:** ${section.content}`);
|
|
305
|
+
break;
|
|
297
306
|
}
|
|
298
307
|
}
|
|
299
308
|
return parts.join("\n\n");
|
package/dist/senses/pipeline.js
CHANGED
|
@@ -57,6 +57,7 @@ const auth_flow_1 = require("../heart/auth/auth-flow");
|
|
|
57
57
|
const tempo_1 = require("../heart/tempo");
|
|
58
58
|
const temporal_view_1 = require("../heart/temporal-view");
|
|
59
59
|
const start_of_turn_packet_1 = require("../heart/start-of-turn-packet");
|
|
60
|
+
const bundle_state_1 = require("../heart/bundle-state");
|
|
60
61
|
const sync_1 = require("../heart/sync");
|
|
61
62
|
const config_1 = require("../heart/config");
|
|
62
63
|
const presence_1 = require("../arc/presence");
|
|
@@ -388,6 +389,13 @@ async function handleInboundTurn(input) {
|
|
|
388
389
|
if (syncFailure) {
|
|
389
390
|
startOfTurnPacket.syncFailure = syncFailure;
|
|
390
391
|
}
|
|
392
|
+
// Structured bundle state detection — surfaces discrete issues the
|
|
393
|
+
// agent can remediate via the bundle_* tools. Runs independently of
|
|
394
|
+
// syncFailure so the two signals coexist during the transition away
|
|
395
|
+
// from the legacy free-form syncFailure string. Always assigned; the
|
|
396
|
+
// packet renderer's empty-filter handles the empty-array case without
|
|
397
|
+
// a separate branch here.
|
|
398
|
+
startOfTurnPacket.bundleState = (0, bundle_state_1.detectBundleState)(agentRoot);
|
|
391
399
|
const capabilities = (0, start_of_turn_packet_1.buildCapabilitiesSection)(agentRoot);
|
|
392
400
|
if (capabilities) {
|
|
393
401
|
startOfTurnPacket.capabilities = capabilities;
|