@ouro.bot/cli 0.1.0-alpha.22 → 0.1.0-alpha.221
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/README.md +187 -191
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/agent.json +3 -2
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +1 -1
- package/changelog.json +1360 -2
- package/dist/arc/attention-types.js +8 -0
- package/dist/arc/cares.js +140 -0
- package/dist/arc/episodes.js +119 -0
- package/dist/arc/intentions.js +133 -0
- package/dist/arc/json-store.js +120 -0
- package/dist/arc/obligations.js +237 -0
- package/dist/arc/presence.js +185 -0
- package/dist/heart/active-work.js +832 -0
- package/dist/heart/agent-entry.js +37 -2
- package/dist/heart/auth/auth-flow.js +444 -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 +111 -0
- package/dist/heart/config-registry.js +305 -0
- package/dist/heart/config.js +59 -30
- package/dist/heart/core.js +601 -145
- package/dist/heart/cross-chat-delivery.js +131 -0
- package/dist/heart/daemon/agent-config-check.js +149 -0
- package/dist/heart/daemon/agent-discovery.js +81 -0
- package/dist/heart/daemon/agent-service.js +360 -0
- package/dist/heart/daemon/cadence.js +70 -0
- package/dist/heart/daemon/cli-defaults.js +557 -0
- package/dist/heart/daemon/cli-exec.js +1847 -0
- package/dist/heart/daemon/cli-parse.js +759 -0
- package/dist/heart/daemon/cli-render.js +316 -0
- package/dist/heart/daemon/cli-types.js +8 -0
- package/dist/heart/daemon/daemon-cli.js +29 -1163
- package/dist/heart/daemon/daemon-entry.js +202 -4
- package/dist/heart/daemon/daemon-health.js +136 -0
- package/dist/heart/daemon/daemon-runtime-sync.js +153 -12
- package/dist/heart/daemon/daemon-tombstone.js +123 -0
- package/dist/heart/daemon/daemon.js +487 -20
- package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
- package/dist/heart/daemon/hooks/bundle-meta.js +115 -1
- package/dist/heart/daemon/inner-status.js +89 -0
- package/dist/heart/daemon/launchd.js +39 -8
- package/dist/heart/daemon/log-tailer.js +4 -3
- package/dist/heart/daemon/message-router.js +17 -8
- package/dist/heart/daemon/os-cron-deps.js +134 -0
- package/dist/heart/daemon/ouro-bot-entry.js +1 -1
- package/dist/heart/daemon/process-manager.js +123 -0
- package/dist/heart/daemon/run-hooks.js +2 -0
- package/dist/heart/daemon/runtime-logging.js +58 -15
- package/dist/heart/daemon/runtime-metadata.js +101 -0
- package/dist/heart/daemon/runtime-mode.js +67 -0
- package/dist/heart/daemon/safe-mode.js +161 -0
- package/dist/heart/daemon/sense-manager.js +72 -3
- package/dist/heart/daemon/session-id-resolver.js +131 -0
- package/dist/heart/daemon/skill-management-installer.js +94 -0
- package/dist/heart/daemon/socket-client.js +202 -0
- package/dist/heart/daemon/task-scheduler.js +3 -25
- package/dist/heart/daemon/thoughts.js +507 -0
- package/dist/heart/delegation.js +62 -0
- package/dist/heart/habits/habit-migration.js +181 -0
- package/dist/heart/habits/habit-parser.js +119 -0
- package/dist/heart/habits/habit-scheduler.js +369 -0
- package/dist/heart/{daemon → hatch}/hatch-flow.js +29 -119
- package/dist/heart/{daemon → hatch}/hatch-specialist.js +3 -3
- package/dist/heart/{daemon → hatch}/specialist-prompt.js +10 -7
- package/dist/heart/{daemon → hatch}/specialist-tools.js +49 -3
- package/dist/heart/identity.js +144 -55
- package/dist/heart/kicks.js +2 -20
- package/dist/heart/mcp/mcp-server.js +608 -0
- package/dist/heart/migrate-config.js +127 -0
- package/dist/heart/model-capabilities.js +48 -0
- package/dist/heart/outlook/outlook-http.js +439 -0
- package/dist/heart/outlook/outlook-read.js +1618 -0
- package/dist/heart/outlook/outlook-render.js +1032 -0
- package/dist/heart/outlook/outlook-types.js +7 -0
- package/dist/heart/outlook/outlook-view.js +194 -0
- package/dist/heart/progress-story.js +42 -0
- package/dist/heart/provider-failover.js +88 -0
- package/dist/heart/provider-ping.js +162 -0
- package/dist/heart/providers/anthropic-token.js +163 -0
- package/dist/heart/providers/anthropic.js +187 -41
- package/dist/heart/providers/azure.js +116 -10
- package/dist/heart/providers/github-copilot.js +157 -0
- package/dist/heart/providers/minimax.js +33 -3
- package/dist/heart/providers/openai-codex.js +51 -16
- package/dist/heart/session-activity.js +172 -0
- package/dist/heart/session-recall.js +216 -0
- package/dist/heart/start-of-turn-packet.js +330 -0
- package/dist/heart/streaming.js +36 -27
- package/dist/heart/sync.js +217 -0
- package/dist/heart/target-resolution.js +127 -0
- package/dist/heart/tempo.js +93 -0
- package/dist/heart/temporal-view.js +41 -0
- package/dist/heart/tool-activity-callbacks.js +36 -0
- package/dist/heart/tool-description.js +135 -0
- package/dist/heart/tool-loop.js +200 -0
- package/dist/heart/turn-context.js +358 -0
- package/dist/heart/turn-coordinator.js +28 -0
- package/dist/heart/versioning/ouro-bot-global-installer.js +128 -0
- package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
- package/dist/heart/{daemon → versioning}/ouro-path-installer.js +78 -35
- package/dist/heart/versioning/ouro-version-manager.js +171 -0
- package/dist/heart/{daemon → versioning}/staged-restart.js +30 -6
- package/dist/heart/{daemon → versioning}/update-checker.js +9 -1
- package/dist/heart/{daemon → versioning}/update-hooks.js +20 -2
- package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +41 -3
- package/dist/mind/associative-recall.js +126 -66
- package/dist/mind/bundle-manifest.js +8 -1
- package/dist/mind/context.js +125 -14
- package/dist/mind/{memory.js → diary.js} +73 -96
- package/dist/mind/embedding-provider.js +60 -0
- package/dist/mind/file-state.js +179 -0
- package/dist/mind/first-impressions.js +16 -2
- package/dist/mind/friends/channel.js +56 -0
- package/dist/mind/friends/group-context.js +144 -0
- package/dist/mind/friends/store-file.js +36 -0
- package/dist/mind/friends/trust-explanation.js +74 -0
- package/dist/mind/friends/types.js +8 -0
- package/dist/mind/journal-index.js +161 -0
- 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 +779 -109
- package/dist/mind/scrutiny.js +173 -0
- package/dist/mind/token-estimate.js +8 -12
- package/dist/nerves/coverage/audit.js +1 -1
- package/dist/nerves/coverage/file-completeness.js +47 -5
- package/dist/nerves/coverage/run-artifacts.js +1 -1
- package/dist/nerves/event-buffer.js +111 -0
- package/dist/nerves/index.js +64 -4
- package/dist/nerves/observation.js +20 -0
- package/dist/nerves/runtime.js +5 -1
- package/dist/outlook-ui/assets/index-Ck8agNeO.js +61 -0
- package/dist/outlook-ui/assets/index-LwChZTgL.css +1 -0
- package/dist/outlook-ui/index.html +15 -0
- package/dist/repertoire/ado-client.js +15 -56
- package/dist/repertoire/ado-semantic.js +11 -5
- package/dist/repertoire/api-client.js +100 -0
- package/dist/repertoire/bitwarden-client.js +290 -0
- package/dist/repertoire/coding/codex-jsonl.js +64 -0
- package/dist/repertoire/coding/context-pack.js +330 -0
- package/dist/repertoire/coding/feedback.js +197 -30
- package/dist/repertoire/coding/manager.js +149 -2
- package/dist/repertoire/coding/spawner.js +55 -9
- package/dist/repertoire/coding/tools.js +170 -7
- package/dist/repertoire/github-client.js +14 -55
- package/dist/repertoire/graph-client.js +11 -52
- package/dist/repertoire/guardrails.js +342 -0
- package/dist/repertoire/mcp-client.js +254 -0
- package/dist/repertoire/mcp-manager.js +251 -0
- package/dist/repertoire/shell-sessions.js +133 -0
- package/dist/repertoire/skills.js +14 -23
- package/dist/repertoire/tasks/board.js +43 -5
- package/dist/repertoire/tasks/fix.js +182 -0
- package/dist/repertoire/tasks/index.js +28 -10
- package/dist/repertoire/tasks/lifecycle.js +2 -2
- package/dist/repertoire/tasks/parser.js +3 -2
- package/dist/repertoire/tasks/scanner.js +194 -37
- package/dist/repertoire/tasks/transitions.js +11 -28
- package/dist/repertoire/tools-base.js +35 -771
- package/dist/repertoire/tools-bluebubbles.js +94 -0
- package/dist/repertoire/tools-bridge.js +141 -0
- package/dist/repertoire/tools-config.js +266 -0
- package/dist/repertoire/tools-continuity.js +248 -0
- package/dist/repertoire/tools-files.js +342 -0
- package/dist/repertoire/tools-flow.js +62 -0
- package/dist/repertoire/tools-github.js +1 -6
- package/dist/repertoire/tools-memory.js +347 -0
- package/dist/repertoire/tools-session.js +721 -0
- package/dist/repertoire/tools-shell.js +120 -0
- package/dist/repertoire/tools-surface.js +242 -0
- package/dist/repertoire/tools-teams.js +12 -59
- package/dist/repertoire/tools-travel.js +125 -0
- package/dist/repertoire/tools-vault.js +185 -0
- package/dist/repertoire/tools.js +132 -124
- package/dist/repertoire/travel-api-client.js +224 -0
- package/dist/scripts/claude-code-hook.js +41 -0
- package/dist/scripts/claude-code-stop-hook.js +47 -0
- package/dist/senses/attention-queue.js +97 -0
- package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +109 -10
- package/dist/senses/bluebubbles/entry.js +13 -0
- package/dist/senses/bluebubbles/inbound-log.js +109 -0
- package/dist/senses/bluebubbles/index.js +1339 -0
- package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +119 -24
- package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +13 -5
- package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +46 -6
- package/dist/senses/bluebubbles/runtime-state.js +109 -0
- package/dist/senses/bluebubbles/session-cleanup.js +72 -0
- package/dist/senses/cli/adapter.js +274 -0
- package/dist/senses/cli/ink-app.js +156 -0
- package/dist/senses/cli/inline-diff.js +64 -0
- package/dist/senses/cli/message-list.js +51 -0
- package/dist/senses/cli/ouro-tui.js +358 -0
- package/dist/senses/cli/spinner-imperative.js +135 -0
- package/dist/senses/cli/spinner.js +101 -0
- package/dist/senses/cli/status-line.js +60 -0
- package/dist/senses/cli/streaming-markdown.js +526 -0
- package/dist/senses/cli/tool-display.js +83 -0
- package/dist/senses/cli/tool-render.js +85 -0
- package/dist/senses/cli/tui-store.js +198 -0
- package/dist/senses/cli/virtual-list.js +35 -0
- package/dist/senses/cli-entry.js +1 -1
- package/dist/senses/cli-layout.js +187 -0
- package/dist/senses/cli.js +503 -244
- package/dist/senses/commands.js +65 -1
- package/dist/senses/continuity.js +94 -0
- package/dist/senses/habit-turn-message.js +108 -0
- package/dist/senses/inner-dialog-worker.js +112 -19
- package/dist/senses/inner-dialog.js +591 -84
- package/dist/senses/pipeline.js +559 -0
- package/dist/senses/shared-turn.js +196 -0
- package/dist/senses/surface-tool.js +68 -0
- package/dist/senses/teams.js +667 -120
- package/dist/senses/trust-gate.js +112 -2
- package/package.json +12 -6
- package/skills/browser-navigation.md +110 -0
- package/skills/configure-dev-tools.md +81 -0
- package/skills/travel-planning.md +143 -0
- package/dist/heart/daemon/subagent-installer.js +0 -134
- package/dist/senses/bluebubbles-entry.js +0 -11
- package/dist/senses/bluebubbles.js +0 -421
- package/dist/senses/debug-activity.js +0 -107
- package/subagents/README.md +0 -73
- package/subagents/work-doer.md +0 -235
- package/subagents/work-merger.md +0 -618
- package/subagents/work-planner.md +0 -382
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +0 -0
- /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
- /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
- /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
- /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
|
@@ -2,8 +2,20 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.formatCodingTail = formatCodingTail;
|
|
4
4
|
exports.attachCodingSessionFeedback = attachCodingSessionFeedback;
|
|
5
|
+
const identity_1 = require("../../heart/identity");
|
|
6
|
+
const socket_client_1 = require("../../heart/daemon/socket-client");
|
|
7
|
+
const obligations_1 = require("../../arc/obligations");
|
|
5
8
|
const runtime_1 = require("../../nerves/runtime");
|
|
6
9
|
const TERMINAL_UPDATE_KINDS = new Set(["completed", "failed", "killed"]);
|
|
10
|
+
const OBLIGATION_WAKE_UPDATE_KINDS = new Set([
|
|
11
|
+
"waiting_input",
|
|
12
|
+
"stalled",
|
|
13
|
+
"completed",
|
|
14
|
+
"failed",
|
|
15
|
+
"killed",
|
|
16
|
+
]);
|
|
17
|
+
const PULL_REQUEST_NUMBER_PATTERN = /\bPR\s*#(\d+)\b/i;
|
|
18
|
+
const PULL_REQUEST_URL_PATTERN = /\/pull\/(\d+)(?:\b|\/)?/i;
|
|
7
19
|
function clip(text, maxLength = 280) {
|
|
8
20
|
const trimmed = text.trim();
|
|
9
21
|
if (trimmed.length <= maxLength)
|
|
@@ -42,25 +54,114 @@ function lastMeaningfulLine(text) {
|
|
|
42
54
|
return clip(lines.at(-1));
|
|
43
55
|
}
|
|
44
56
|
function formatSessionLabel(session) {
|
|
45
|
-
|
|
57
|
+
const origin = session.originSession
|
|
58
|
+
? ` for ${session.originSession.channel}/${session.originSession.key}`
|
|
59
|
+
: "";
|
|
60
|
+
return `${session.runner} ${session.id}${origin}`;
|
|
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;
|
|
46
116
|
}
|
|
47
117
|
function isSafeProgressSnippet(snippet) {
|
|
118
|
+
const normalized = snippet.trim();
|
|
48
119
|
const wordCount = snippet.split(/\s+/).filter(Boolean).length;
|
|
49
|
-
return (
|
|
120
|
+
return (normalized.length <= 80
|
|
121
|
+
&& wordCount >= 2
|
|
50
122
|
&& wordCount <= 8
|
|
51
|
-
&&
|
|
52
|
-
&& !
|
|
53
|
-
&&
|
|
54
|
-
&&
|
|
55
|
-
&& !/^
|
|
56
|
-
&& !/^
|
|
57
|
-
&& !/^
|
|
123
|
+
&& /[A-Za-z]{3,}/.test(normalized)
|
|
124
|
+
&& !normalized.includes(":")
|
|
125
|
+
&& !/[{}\[\]();]/.test(normalized)
|
|
126
|
+
&& !normalized.startsWith("**")
|
|
127
|
+
&& !/^Respond with\b/i.test(normalized)
|
|
128
|
+
&& !/^Coding session metadata\b/i.test(normalized)
|
|
129
|
+
&& !/^sessionId\b/i.test(normalized)
|
|
130
|
+
&& !/^taskRef\b/i.test(normalized)
|
|
131
|
+
&& !/^parentAgent\b/i.test(normalized));
|
|
58
132
|
}
|
|
59
133
|
function pickUpdateSnippet(update) {
|
|
60
|
-
|
|
134
|
+
const checkpoint = update.session.checkpoint?.trim() || null;
|
|
135
|
+
return (checkpoint
|
|
136
|
+
?? lastMeaningfulLine(update.text)
|
|
61
137
|
?? lastMeaningfulLine(update.session.stderrTail)
|
|
62
138
|
?? lastMeaningfulLine(update.session.stdoutTail));
|
|
63
139
|
}
|
|
140
|
+
function renderValue(text) {
|
|
141
|
+
const trimmed = text?.trim();
|
|
142
|
+
return trimmed && trimmed.length > 0 ? trimmed : "(empty)";
|
|
143
|
+
}
|
|
144
|
+
function renderPath(text) {
|
|
145
|
+
return text && text.trim().length > 0 ? text : "(none)";
|
|
146
|
+
}
|
|
147
|
+
function formatCodingTail(session) {
|
|
148
|
+
const stdout = renderValue(session.stdoutTail);
|
|
149
|
+
const stderr = renderValue(session.stderrTail);
|
|
150
|
+
return [
|
|
151
|
+
`sessionId: ${session.id}`,
|
|
152
|
+
`runner: ${session.runner}`,
|
|
153
|
+
`status: ${session.status}`,
|
|
154
|
+
`checkpoint: ${renderValue(session.checkpoint ?? undefined)}`,
|
|
155
|
+
`artifactPath: ${renderPath(session.artifactPath)}`,
|
|
156
|
+
`workdir: ${session.workdir}`,
|
|
157
|
+
"",
|
|
158
|
+
"[stdout]",
|
|
159
|
+
stdout,
|
|
160
|
+
"",
|
|
161
|
+
"[stderr]",
|
|
162
|
+
stderr,
|
|
163
|
+
].join("\n");
|
|
164
|
+
}
|
|
64
165
|
function formatUpdateMessage(update) {
|
|
65
166
|
const label = formatSessionLabel(update.session);
|
|
66
167
|
const snippet = pickUpdateSnippet(update);
|
|
@@ -81,26 +182,88 @@ function formatUpdateMessage(update) {
|
|
|
81
182
|
return `${label} started`;
|
|
82
183
|
}
|
|
83
184
|
}
|
|
84
|
-
function
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
185
|
+
function formatReportBackMessage(update, baseMessage) {
|
|
186
|
+
if (!baseMessage)
|
|
187
|
+
return null;
|
|
188
|
+
if (!update.session.obligationId || !update.session.originSession) {
|
|
189
|
+
return baseMessage;
|
|
190
|
+
}
|
|
191
|
+
const milestone = deriveObligationMilestone(update);
|
|
192
|
+
const extraLines = [];
|
|
193
|
+
if (milestone?.currentArtifact) {
|
|
194
|
+
extraLines.push(`current artifact: ${milestone.currentArtifact}`);
|
|
195
|
+
}
|
|
196
|
+
if (milestone?.nextAction) {
|
|
197
|
+
extraLines.push(`next: ${milestone.nextAction}`);
|
|
198
|
+
}
|
|
199
|
+
return extraLines.length > 0 ? `${baseMessage}\n${extraLines.join("\n")}` : baseMessage;
|
|
200
|
+
}
|
|
201
|
+
function obligationNoteFromUpdate(update) {
|
|
202
|
+
const snippet = pickUpdateSnippet(update);
|
|
203
|
+
switch (update.kind) {
|
|
204
|
+
case "spawned":
|
|
205
|
+
return update.session.originSession
|
|
206
|
+
? `coding session started for ${update.session.originSession.channel}/${update.session.originSession.key}`
|
|
207
|
+
: "coding session started";
|
|
208
|
+
case "progress":
|
|
209
|
+
return snippet ? `coding session progress: ${snippet}` : null;
|
|
210
|
+
case "waiting_input":
|
|
211
|
+
return snippet ? `coding session waiting: ${snippet}` : "coding session waiting for input";
|
|
212
|
+
case "stalled":
|
|
213
|
+
return snippet ? `coding session stalled: ${snippet}` : "coding session stalled";
|
|
214
|
+
case "completed":
|
|
215
|
+
return snippet
|
|
216
|
+
? `coding session completed: ${snippet}; merge/update still pending`
|
|
217
|
+
: "coding session completed; merge/update still pending";
|
|
218
|
+
case "failed":
|
|
219
|
+
return snippet ? `coding session failed: ${snippet}` : "coding session failed";
|
|
220
|
+
case "killed":
|
|
221
|
+
return "coding session killed";
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
function syncObligationFromUpdate(update) {
|
|
225
|
+
const obligationId = update.session.obligationId;
|
|
226
|
+
if (!obligationId)
|
|
227
|
+
return;
|
|
228
|
+
const milestone = deriveObligationMilestone(update);
|
|
229
|
+
try {
|
|
230
|
+
(0, obligations_1.advanceObligation)((0, identity_1.getAgentRoot)(), obligationId, {
|
|
231
|
+
status: milestone?.status ?? "investigating",
|
|
232
|
+
currentSurface: milestone?.currentSurface ?? { kind: "coding", label: `${update.session.runner} ${update.session.id}` },
|
|
233
|
+
currentArtifact: milestone?.currentArtifact,
|
|
234
|
+
nextAction: milestone?.nextAction,
|
|
235
|
+
latestNote: obligationNoteFromUpdate(update) ?? undefined,
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
catch {
|
|
239
|
+
// Detached feedback should still reach the human even if obligation sync is unavailable.
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
async function wakeInnerDialogForObligation(update) {
|
|
243
|
+
if (!update.session.obligationId || !OBLIGATION_WAKE_UPDATE_KINDS.has(update.kind)) {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
try {
|
|
247
|
+
await (0, socket_client_1.requestInnerWake)((0, identity_1.getAgentName)());
|
|
248
|
+
}
|
|
249
|
+
catch (error) {
|
|
250
|
+
(0, runtime_1.emitNervesEvent)({
|
|
251
|
+
level: "warn",
|
|
252
|
+
component: "repertoire",
|
|
253
|
+
event: "repertoire.coding_feedback_wake_error",
|
|
254
|
+
message: "coding feedback wake request failed",
|
|
255
|
+
meta: {
|
|
256
|
+
sessionId: update.session.id,
|
|
257
|
+
kind: update.kind,
|
|
258
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
259
|
+
},
|
|
260
|
+
});
|
|
261
|
+
}
|
|
99
262
|
}
|
|
100
263
|
function attachCodingSessionFeedback(manager, session, target) {
|
|
101
264
|
let lastMessage = "";
|
|
102
265
|
let closed = false;
|
|
103
|
-
let unsubscribe =
|
|
266
|
+
let unsubscribe = null;
|
|
104
267
|
const sendMessage = (message) => {
|
|
105
268
|
if (closed || !message || message === lastMessage) {
|
|
106
269
|
return;
|
|
@@ -119,16 +282,20 @@ function attachCodingSessionFeedback(manager, session, target) {
|
|
|
119
282
|
});
|
|
120
283
|
});
|
|
121
284
|
};
|
|
122
|
-
|
|
285
|
+
const spawnedUpdate = { kind: "spawned", session };
|
|
286
|
+
syncObligationFromUpdate(spawnedUpdate);
|
|
287
|
+
sendMessage(formatReportBackMessage(spawnedUpdate, formatUpdateMessage(spawnedUpdate)));
|
|
123
288
|
unsubscribe = manager.subscribe(session.id, async (update) => {
|
|
124
|
-
|
|
289
|
+
syncObligationFromUpdate(update);
|
|
290
|
+
sendMessage(formatReportBackMessage(update, formatUpdateMessage(update)));
|
|
291
|
+
await wakeInnerDialogForObligation(update);
|
|
125
292
|
if (TERMINAL_UPDATE_KINDS.has(update.kind)) {
|
|
126
293
|
closed = true;
|
|
127
|
-
unsubscribe();
|
|
294
|
+
unsubscribe?.();
|
|
128
295
|
}
|
|
129
296
|
});
|
|
130
297
|
return () => {
|
|
131
298
|
closed = true;
|
|
132
|
-
unsubscribe();
|
|
299
|
+
unsubscribe?.();
|
|
133
300
|
};
|
|
134
301
|
}
|
|
@@ -35,7 +35,6 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.CodingSessionManager = void 0;
|
|
37
37
|
const fs = __importStar(require("fs"));
|
|
38
|
-
const os = __importStar(require("os"));
|
|
39
38
|
const path = __importStar(require("path"));
|
|
40
39
|
const identity_1 = require("../../heart/identity");
|
|
41
40
|
const runtime_1 = require("../../nerves/runtime");
|
|
@@ -49,7 +48,10 @@ function safeAgentName() {
|
|
|
49
48
|
}
|
|
50
49
|
}
|
|
51
50
|
function defaultStateFilePath(agentName) {
|
|
52
|
-
return path.join(
|
|
51
|
+
return path.join((0, identity_1.getAgentRoot)(agentName), "state", "coding", "sessions.json");
|
|
52
|
+
}
|
|
53
|
+
function defaultArtifactDirPath(agentName) {
|
|
54
|
+
return path.join((0, identity_1.getAgentRoot)(agentName), "state", "coding", "sessions");
|
|
53
55
|
}
|
|
54
56
|
function isPidAlive(pid) {
|
|
55
57
|
try {
|
|
@@ -63,6 +65,9 @@ function isPidAlive(pid) {
|
|
|
63
65
|
function cloneSession(session) {
|
|
64
66
|
return {
|
|
65
67
|
...session,
|
|
68
|
+
originSession: session.originSession ? { ...session.originSession } : undefined,
|
|
69
|
+
checkpoint: session.checkpoint ?? null,
|
|
70
|
+
artifactPath: session.artifactPath,
|
|
66
71
|
stdoutTail: session.stdoutTail,
|
|
67
72
|
stderrTail: session.stderrTail,
|
|
68
73
|
failure: session.failure
|
|
@@ -86,6 +91,46 @@ function appendTail(existing, nextChunk, maxLength = 2000) {
|
|
|
86
91
|
const combined = `${existing}${nextChunk}`;
|
|
87
92
|
return combined.length <= maxLength ? combined : combined.slice(combined.length - maxLength);
|
|
88
93
|
}
|
|
94
|
+
function compactText(text) {
|
|
95
|
+
return text.replace(/\s+/g, " ").trim();
|
|
96
|
+
}
|
|
97
|
+
function clipText(text, maxLength = 240) {
|
|
98
|
+
return text.length <= maxLength ? text : `${text.slice(0, maxLength - 3)}...`;
|
|
99
|
+
}
|
|
100
|
+
function latestMeaningfulLine(text) {
|
|
101
|
+
const lines = text
|
|
102
|
+
.split(/\r?\n/)
|
|
103
|
+
.map((line) => compactText(line))
|
|
104
|
+
.filter(Boolean);
|
|
105
|
+
if (lines.length === 0)
|
|
106
|
+
return null;
|
|
107
|
+
return clipText(lines.at(-1));
|
|
108
|
+
}
|
|
109
|
+
function fallbackCheckpoint(status, code, signal) {
|
|
110
|
+
switch (status) {
|
|
111
|
+
case "waiting_input":
|
|
112
|
+
return "needs input";
|
|
113
|
+
case "stalled":
|
|
114
|
+
return "no recent output";
|
|
115
|
+
case "completed":
|
|
116
|
+
return "completed";
|
|
117
|
+
case "failed":
|
|
118
|
+
if (code !== null)
|
|
119
|
+
return `exit code ${code}`;
|
|
120
|
+
if (signal)
|
|
121
|
+
return `terminated by ${signal}`;
|
|
122
|
+
return "failed";
|
|
123
|
+
case "killed":
|
|
124
|
+
return "terminated by parent agent";
|
|
125
|
+
default:
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
function deriveCheckpoint(session) {
|
|
130
|
+
return (latestMeaningfulLine(session.stderrTail)
|
|
131
|
+
?? latestMeaningfulLine(session.stdoutTail)
|
|
132
|
+
?? fallbackCheckpoint(session.status, session.lastExitCode, session.lastSignal));
|
|
133
|
+
}
|
|
89
134
|
function isSpawnCodingResult(value) {
|
|
90
135
|
return typeof value === "object" && value !== null && "process" in value;
|
|
91
136
|
}
|
|
@@ -123,6 +168,7 @@ class CodingSessionManager {
|
|
|
123
168
|
maxRestarts;
|
|
124
169
|
defaultStallThresholdMs;
|
|
125
170
|
stateFilePath;
|
|
171
|
+
artifactDirPath;
|
|
126
172
|
existsSync;
|
|
127
173
|
readFileSync;
|
|
128
174
|
writeFileSync;
|
|
@@ -142,6 +188,8 @@ class CodingSessionManager {
|
|
|
142
188
|
this.pidAlive = options.pidAlive ?? isPidAlive;
|
|
143
189
|
this.agentName = options.agentName ?? safeAgentName();
|
|
144
190
|
this.stateFilePath = options.stateFilePath ?? defaultStateFilePath(this.agentName);
|
|
191
|
+
this.artifactDirPath = options.artifactDirPath
|
|
192
|
+
?? (options.stateFilePath ? path.dirname(options.stateFilePath) : defaultArtifactDirPath(this.agentName));
|
|
145
193
|
this.loadPersistedState();
|
|
146
194
|
}
|
|
147
195
|
async spawnSession(request) {
|
|
@@ -158,8 +206,12 @@ class CodingSessionManager {
|
|
|
158
206
|
runner: normalizedRequest.runner,
|
|
159
207
|
workdir: normalizedRequest.workdir,
|
|
160
208
|
taskRef: normalizedRequest.taskRef,
|
|
209
|
+
originSession: normalizedRequest.originSession ? { ...normalizedRequest.originSession } : undefined,
|
|
210
|
+
obligationId: normalizedRequest.obligationId,
|
|
161
211
|
scopeFile: normalizedRequest.scopeFile,
|
|
162
212
|
stateFile: normalizedRequest.stateFile,
|
|
213
|
+
checkpoint: null,
|
|
214
|
+
artifactPath: this.artifactPathFor(id),
|
|
163
215
|
status: "spawning",
|
|
164
216
|
stdoutTail: "",
|
|
165
217
|
stderrTail: "",
|
|
@@ -246,6 +298,7 @@ class CodingSessionManager {
|
|
|
246
298
|
record.process.kill("SIGTERM");
|
|
247
299
|
record.process = null;
|
|
248
300
|
record.session.status = "killed";
|
|
301
|
+
record.session.checkpoint = "terminated by parent agent";
|
|
249
302
|
record.session.endedAt = this.nowIso();
|
|
250
303
|
(0, runtime_1.emitNervesEvent)({
|
|
251
304
|
component: "repertoire",
|
|
@@ -268,6 +321,7 @@ class CodingSessionManager {
|
|
|
268
321
|
continue;
|
|
269
322
|
stalled += 1;
|
|
270
323
|
record.session.status = "stalled";
|
|
324
|
+
record.session.checkpoint = deriveCheckpoint(record.session);
|
|
271
325
|
(0, runtime_1.emitNervesEvent)({
|
|
272
326
|
level: "warn",
|
|
273
327
|
component: "repertoire",
|
|
@@ -293,6 +347,7 @@ class CodingSessionManager {
|
|
|
293
347
|
record.process = null;
|
|
294
348
|
if (record.session.status === "running" || record.session.status === "spawning") {
|
|
295
349
|
record.session.status = "killed";
|
|
350
|
+
record.session.checkpoint = "terminated during manager shutdown";
|
|
296
351
|
record.session.endedAt = this.nowIso();
|
|
297
352
|
}
|
|
298
353
|
}
|
|
@@ -337,6 +392,13 @@ class CodingSessionManager {
|
|
|
337
392
|
record.session.endedAt = this.nowIso();
|
|
338
393
|
updateKind = "completed";
|
|
339
394
|
}
|
|
395
|
+
const checkpoint = latestMeaningfulLine(text);
|
|
396
|
+
if (checkpoint) {
|
|
397
|
+
record.session.checkpoint = checkpoint;
|
|
398
|
+
}
|
|
399
|
+
else if (!record.session.checkpoint) {
|
|
400
|
+
record.session.checkpoint = deriveCheckpoint(record.session);
|
|
401
|
+
}
|
|
340
402
|
(0, runtime_1.emitNervesEvent)({
|
|
341
403
|
component: "repertoire",
|
|
342
404
|
event: "repertoire.coding_session_output",
|
|
@@ -360,12 +422,14 @@ class CodingSessionManager {
|
|
|
360
422
|
record.session.lastSignal = signal;
|
|
361
423
|
if (record.session.status === "killed" || record.session.status === "completed") {
|
|
362
424
|
record.session.endedAt = this.nowIso();
|
|
425
|
+
record.session.checkpoint = deriveCheckpoint(record.session);
|
|
363
426
|
this.persistState();
|
|
364
427
|
return;
|
|
365
428
|
}
|
|
366
429
|
if (code === 0) {
|
|
367
430
|
record.session.status = "completed";
|
|
368
431
|
record.session.endedAt = this.nowIso();
|
|
432
|
+
record.session.checkpoint = deriveCheckpoint(record.session);
|
|
369
433
|
this.persistState();
|
|
370
434
|
this.notifyListeners(record.session.id, { kind: "completed", session: cloneSession(record.session) });
|
|
371
435
|
return;
|
|
@@ -377,6 +441,7 @@ class CodingSessionManager {
|
|
|
377
441
|
record.session.status = "failed";
|
|
378
442
|
record.session.endedAt = this.nowIso();
|
|
379
443
|
record.session.failure = defaultFailureDiagnostics(code, signal, record.command, record.args, record.stdoutTail, record.stderrTail);
|
|
444
|
+
record.session.checkpoint = deriveCheckpoint(record.session);
|
|
380
445
|
(0, runtime_1.emitNervesEvent)({
|
|
381
446
|
level: "error",
|
|
382
447
|
component: "repertoire",
|
|
@@ -402,6 +467,7 @@ class CodingSessionManager {
|
|
|
402
467
|
record.session.lastActivityAt = this.nowIso();
|
|
403
468
|
record.session.endedAt = null;
|
|
404
469
|
record.session.failure = null;
|
|
470
|
+
record.session.checkpoint = `restarted after ${reason}`;
|
|
405
471
|
this.attachProcessListeners(record);
|
|
406
472
|
(0, runtime_1.emitNervesEvent)({
|
|
407
473
|
level: "warn",
|
|
@@ -483,15 +549,21 @@ class CodingSessionManager {
|
|
|
483
549
|
}
|
|
484
550
|
const normalizedRequest = {
|
|
485
551
|
...request,
|
|
552
|
+
originSession: request.originSession ? { ...request.originSession } : undefined,
|
|
486
553
|
sessionId: request.sessionId ?? session.id,
|
|
554
|
+
obligationId: request.obligationId,
|
|
487
555
|
parentAgent: request.parentAgent ?? this.agentName,
|
|
488
556
|
};
|
|
489
557
|
const normalizedSession = {
|
|
490
558
|
...session,
|
|
491
559
|
taskRef: session.taskRef ?? normalizedRequest.taskRef,
|
|
560
|
+
originSession: session.originSession ?? normalizedRequest.originSession,
|
|
561
|
+
obligationId: session.obligationId ?? normalizedRequest.obligationId,
|
|
492
562
|
failure: session.failure ?? null,
|
|
493
563
|
stdoutTail: session.stdoutTail ?? session.failure?.stdoutTail ?? "",
|
|
494
564
|
stderrTail: session.stderrTail ?? session.failure?.stderrTail ?? "",
|
|
565
|
+
checkpoint: typeof session.checkpoint === "string" ? session.checkpoint : null,
|
|
566
|
+
artifactPath: typeof session.artifactPath === "string" ? session.artifactPath : this.artifactPathFor(session.id),
|
|
495
567
|
};
|
|
496
568
|
if (typeof normalizedSession.pid === "number") {
|
|
497
569
|
const alive = this.pidAlive(normalizedSession.pid);
|
|
@@ -504,6 +576,7 @@ class CodingSessionManager {
|
|
|
504
576
|
normalizedSession.pid = null;
|
|
505
577
|
}
|
|
506
578
|
}
|
|
579
|
+
normalizedSession.checkpoint = normalizedSession.checkpoint ?? deriveCheckpoint(normalizedSession);
|
|
507
580
|
this.records.set(normalizedSession.id, {
|
|
508
581
|
request: normalizedRequest,
|
|
509
582
|
session: normalizedSession,
|
|
@@ -543,6 +616,80 @@ class CodingSessionManager {
|
|
|
543
616
|
meta: { path: this.stateFilePath, reason: error instanceof Error ? error.message : String(error) },
|
|
544
617
|
});
|
|
545
618
|
}
|
|
619
|
+
this.persistArtifacts();
|
|
620
|
+
}
|
|
621
|
+
artifactPathFor(sessionId) {
|
|
622
|
+
return path.join(this.artifactDirPath, `${sessionId}.md`);
|
|
623
|
+
}
|
|
624
|
+
renderArtifact(record) {
|
|
625
|
+
const { request, session } = record;
|
|
626
|
+
const stdout = session.stdoutTail.trim() || "(empty)";
|
|
627
|
+
const stderr = session.stderrTail.trim() || "(empty)";
|
|
628
|
+
const lines = [
|
|
629
|
+
"# Coding Session Artifact",
|
|
630
|
+
"",
|
|
631
|
+
"## Session",
|
|
632
|
+
`id: ${session.id}`,
|
|
633
|
+
`runner: ${session.runner}`,
|
|
634
|
+
`status: ${session.status}`,
|
|
635
|
+
`taskRef: ${session.taskRef ?? "unassigned"}`,
|
|
636
|
+
`workdir: ${session.workdir}`,
|
|
637
|
+
`startedAt: ${session.startedAt}`,
|
|
638
|
+
`lastActivityAt: ${session.lastActivityAt}`,
|
|
639
|
+
`endedAt: ${session.endedAt ?? "active"}`,
|
|
640
|
+
`pid: ${session.pid ?? "none"}`,
|
|
641
|
+
`restarts: ${session.restartCount}`,
|
|
642
|
+
`checkpoint: ${session.checkpoint ?? "none"}`,
|
|
643
|
+
`scopeFile: ${session.scopeFile ?? "none"}`,
|
|
644
|
+
`stateFile: ${session.stateFile ?? "none"}`,
|
|
645
|
+
"",
|
|
646
|
+
"## Request",
|
|
647
|
+
request.prompt,
|
|
648
|
+
"",
|
|
649
|
+
"## Stdout Tail",
|
|
650
|
+
stdout,
|
|
651
|
+
"",
|
|
652
|
+
"## Stderr Tail",
|
|
653
|
+
stderr,
|
|
654
|
+
];
|
|
655
|
+
if (session.failure) {
|
|
656
|
+
lines.push("", "## Failure", `command: ${session.failure.command}`, `args: ${session.failure.args.join(" ") || "(none)"}`, `code: ${session.failure.code ?? "null"}`, `signal: ${session.failure.signal ?? "null"}`);
|
|
657
|
+
}
|
|
658
|
+
return `${lines.join("\n")}\n`;
|
|
659
|
+
}
|
|
660
|
+
persistArtifacts() {
|
|
661
|
+
try {
|
|
662
|
+
this.mkdirSync(this.artifactDirPath, { recursive: true });
|
|
663
|
+
}
|
|
664
|
+
catch (error) {
|
|
665
|
+
(0, runtime_1.emitNervesEvent)({
|
|
666
|
+
level: "warn",
|
|
667
|
+
component: "repertoire",
|
|
668
|
+
event: "repertoire.coding_artifact_persist_error",
|
|
669
|
+
message: "failed preparing coding artifact directory",
|
|
670
|
+
meta: { path: this.artifactDirPath, reason: error instanceof Error ? error.message : String(error) },
|
|
671
|
+
});
|
|
672
|
+
return;
|
|
673
|
+
}
|
|
674
|
+
for (const record of this.records.values()) {
|
|
675
|
+
try {
|
|
676
|
+
record.session.artifactPath = record.session.artifactPath ?? this.artifactPathFor(record.session.id);
|
|
677
|
+
this.writeFileSync(record.session.artifactPath, this.renderArtifact(record), "utf-8");
|
|
678
|
+
}
|
|
679
|
+
catch (error) {
|
|
680
|
+
(0, runtime_1.emitNervesEvent)({
|
|
681
|
+
level: "warn",
|
|
682
|
+
component: "repertoire",
|
|
683
|
+
event: "repertoire.coding_artifact_persist_error",
|
|
684
|
+
message: "failed writing coding session artifact",
|
|
685
|
+
meta: {
|
|
686
|
+
id: record.session.id,
|
|
687
|
+
path: record.session.artifactPath ?? this.artifactPathFor(record.session.id),
|
|
688
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
689
|
+
},
|
|
690
|
+
});
|
|
691
|
+
}
|
|
692
|
+
}
|
|
546
693
|
}
|
|
547
694
|
}
|
|
548
695
|
exports.CodingSessionManager = CodingSessionManager;
|
|
@@ -36,8 +36,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.spawnCodingProcess = spawnCodingProcess;
|
|
37
37
|
const child_process_1 = require("child_process");
|
|
38
38
|
const fs = __importStar(require("fs"));
|
|
39
|
+
const os = __importStar(require("os"));
|
|
40
|
+
const path = __importStar(require("path"));
|
|
39
41
|
const runtime_1 = require("../../nerves/runtime");
|
|
40
|
-
function buildCommandArgs(runner, workdir) {
|
|
42
|
+
function buildCommandArgs(runner, workdir, parentAgent) {
|
|
41
43
|
if (runner === "claude") {
|
|
42
44
|
return {
|
|
43
45
|
command: "claude",
|
|
@@ -53,25 +55,65 @@ function buildCommandArgs(runner, workdir) {
|
|
|
53
55
|
],
|
|
54
56
|
};
|
|
55
57
|
}
|
|
58
|
+
const agent = parentAgent ?? "unknown";
|
|
59
|
+
// Use absolute path to ouro-entry.js so MCP works in both dev and installed mode
|
|
60
|
+
// __dirname at runtime is dist/repertoire/coding/ — go up 2 levels to dist/
|
|
61
|
+
const distRoot = path.resolve(__dirname, "..", "..");
|
|
62
|
+
const ouroEntryPath = path.join(distRoot, "heart", "daemon", "ouro-entry.js");
|
|
56
63
|
return {
|
|
57
64
|
command: "codex",
|
|
58
|
-
args: [
|
|
65
|
+
args: [
|
|
66
|
+
"exec",
|
|
67
|
+
"--skip-git-repo-check",
|
|
68
|
+
"--cd",
|
|
69
|
+
workdir,
|
|
70
|
+
"--ephemeral",
|
|
71
|
+
"--json",
|
|
72
|
+
"-c",
|
|
73
|
+
`mcp_servers.ouro.command=node`,
|
|
74
|
+
"-c",
|
|
75
|
+
`mcp_servers.ouro.args=["${ouroEntryPath}","mcp-serve","--agent","${agent}"]`,
|
|
76
|
+
],
|
|
59
77
|
};
|
|
60
78
|
}
|
|
79
|
+
function buildSpawnEnv(baseEnv, homeDir) {
|
|
80
|
+
const binDir = path.join(homeDir, ".ouro-cli", "bin");
|
|
81
|
+
const existingPath = baseEnv.PATH ?? "";
|
|
82
|
+
const pathEntries = existingPath.split(path.delimiter).filter((entry) => entry.length > 0);
|
|
83
|
+
if (!pathEntries.includes(binDir)) {
|
|
84
|
+
pathEntries.unshift(binDir);
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
...baseEnv,
|
|
88
|
+
PATH: pathEntries.join(path.delimiter),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function appendFileSection(sections, label, filePath, deps) {
|
|
92
|
+
if (!filePath || !deps.existsSync(filePath))
|
|
93
|
+
return;
|
|
94
|
+
const content = deps.readFileSync(filePath, "utf-8").trim();
|
|
95
|
+
if (content.length === 0)
|
|
96
|
+
return;
|
|
97
|
+
sections.push(`${label} (${filePath}):\n${content}`);
|
|
98
|
+
}
|
|
61
99
|
function buildPrompt(request, deps) {
|
|
62
100
|
const sections = [];
|
|
101
|
+
sections.push([
|
|
102
|
+
"Execution contract:",
|
|
103
|
+
"- You are a subordinate coding session launched by a parent Ouro agent.",
|
|
104
|
+
"- Execute the concrete request in the supplied workdir directly.",
|
|
105
|
+
"- Do not switch into planning/doing workflows, approval gates, or repo-management rituals unless the request explicitly asks for them.",
|
|
106
|
+
"- Treat the request, scope file, and state file as the authoritative briefing for this session.",
|
|
107
|
+
"- Prefer direct execution and verification over narration.",
|
|
108
|
+
].join("\n"));
|
|
63
109
|
sections.push([
|
|
64
110
|
"Coding session metadata:",
|
|
65
111
|
`sessionId: ${request.sessionId ?? "pending"}`,
|
|
66
112
|
`parentAgent: ${request.parentAgent ?? "unknown"}`,
|
|
67
113
|
`taskRef: ${request.taskRef ?? "unassigned"}`,
|
|
68
114
|
].join("\n"));
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
if (stateContent.length > 0) {
|
|
72
|
-
sections.push(`State file (${request.stateFile}):\n${stateContent}`);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
115
|
+
appendFileSection(sections, "Scope file", request.scopeFile, deps);
|
|
116
|
+
appendFileSection(sections, "State file", request.stateFile, deps);
|
|
75
117
|
sections.push(request.prompt);
|
|
76
118
|
return sections.join("\n\n---\n\n");
|
|
77
119
|
}
|
|
@@ -79,8 +121,11 @@ function spawnCodingProcess(request, deps = {}) {
|
|
|
79
121
|
const spawnFn = deps.spawnFn ?? ((command, args, options) => (0, child_process_1.spawn)(command, args, options));
|
|
80
122
|
const existsSync = deps.existsSync ?? fs.existsSync;
|
|
81
123
|
const readFileSync = deps.readFileSync ?? fs.readFileSync;
|
|
124
|
+
const homeDir = deps.homeDir ?? os.homedir();
|
|
125
|
+
const baseEnv = deps.baseEnv ?? process.env;
|
|
82
126
|
const prompt = buildPrompt(request, { existsSync, readFileSync });
|
|
83
|
-
const { command, args } = buildCommandArgs(request.runner, request.workdir);
|
|
127
|
+
const { command, args } = buildCommandArgs(request.runner, request.workdir, request.parentAgent);
|
|
128
|
+
const env = buildSpawnEnv(baseEnv, homeDir);
|
|
84
129
|
(0, runtime_1.emitNervesEvent)({
|
|
85
130
|
component: "repertoire",
|
|
86
131
|
event: "repertoire.coding_spawn_start",
|
|
@@ -89,6 +134,7 @@ function spawnCodingProcess(request, deps = {}) {
|
|
|
89
134
|
});
|
|
90
135
|
const proc = spawnFn(command, args, {
|
|
91
136
|
cwd: request.workdir,
|
|
137
|
+
env,
|
|
92
138
|
stdio: ["pipe", "pipe", "pipe"],
|
|
93
139
|
});
|
|
94
140
|
proc.stdin.end(`${prompt}\n`);
|