@ouro.bot/cli 0.1.0-alpha.4 → 0.1.0-alpha.400
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 +208 -184
- package/SerpentGuide.ouro/agent.json +82 -0
- package/SerpentGuide.ouro/psyche/SOUL.md +25 -0
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +2 -2
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +1 -1
- package/assets/ouroboros.png +0 -0
- package/changelog.json +2610 -0
- package/dist/arc/attention-types.js +8 -0
- package/dist/arc/cares.js +140 -0
- package/dist/arc/episodes.js +117 -0
- package/dist/arc/intentions.js +133 -0
- package/dist/arc/json-store.js +117 -0
- package/dist/arc/obligations.js +237 -0
- package/dist/arc/packets.js +193 -0
- package/dist/arc/presence.js +185 -0
- package/dist/arc/task-lifecycle.js +65 -0
- package/dist/heart/active-work.js +832 -0
- package/dist/heart/agent-entry.js +58 -3
- package/dist/heart/attachments/image-normalize.js +194 -0
- package/dist/heart/attachments/materialize.js +97 -0
- package/dist/heart/attachments/originals.js +88 -0
- package/dist/heart/attachments/render.js +29 -0
- package/dist/heart/attachments/sources/adapter.js +2 -0
- package/dist/heart/attachments/sources/bluebubbles.js +156 -0
- package/dist/heart/attachments/sources/cli-local-file.js +78 -0
- package/dist/heart/attachments/sources/index.js +16 -0
- package/dist/heart/attachments/store.js +103 -0
- package/dist/heart/attachments/types.js +93 -0
- package/dist/heart/auth/auth-flow.js +417 -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/bundle-state.js +168 -0
- package/dist/heart/commitments.js +111 -0
- package/dist/heart/config-registry.js +304 -0
- package/dist/heart/config.js +176 -130
- package/dist/heart/core.js +872 -255
- package/dist/heart/cross-chat-delivery.js +131 -0
- package/dist/heart/daemon/agent-config-check.js +397 -0
- package/dist/heart/daemon/agent-discovery.js +157 -0
- package/dist/heart/daemon/agent-service.js +360 -0
- package/dist/heart/daemon/agentic-repair.js +213 -0
- package/dist/heart/daemon/bluebubbles-health-diagnostics.js +122 -0
- package/dist/heart/daemon/cadence.js +70 -0
- package/dist/heart/daemon/cli-defaults.js +599 -0
- package/dist/heart/daemon/cli-exec.js +3616 -0
- package/dist/heart/daemon/cli-help.js +396 -0
- package/dist/heart/daemon/cli-parse.js +1118 -0
- package/dist/heart/daemon/cli-render-doctor.js +57 -0
- package/dist/heart/daemon/cli-render.js +560 -0
- package/dist/heart/daemon/cli-types.js +8 -0
- package/dist/heart/daemon/daemon-cli.js +29 -673
- package/dist/heart/daemon/daemon-entry.js +370 -8
- package/dist/heart/daemon/daemon-health.js +141 -0
- package/dist/heart/daemon/daemon-runtime-sync.js +235 -0
- package/dist/heart/daemon/daemon-tombstone.js +236 -0
- package/dist/heart/daemon/daemon.js +813 -19
- package/dist/heart/daemon/doctor-types.js +8 -0
- package/dist/heart/daemon/doctor.js +419 -0
- package/dist/heart/daemon/health-monitor.js +79 -1
- package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
- package/dist/heart/daemon/hooks/bundle-meta.js +206 -0
- package/dist/heart/daemon/http-health-probe.js +80 -0
- package/dist/heart/daemon/inner-status.js +89 -0
- package/dist/heart/daemon/interactive-repair.js +209 -0
- package/dist/heart/daemon/launchd.js +171 -0
- package/dist/heart/daemon/log-tailer.js +82 -12
- package/dist/heart/daemon/logs-prune.js +105 -0
- 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 +4 -2
- package/dist/heart/daemon/ouro-entry.js +3 -1
- package/dist/heart/daemon/process-manager.js +202 -1
- package/dist/heart/daemon/provider-discovery.js +137 -0
- package/dist/heart/daemon/pulse.js +475 -0
- package/dist/heart/daemon/readiness-repair.js +216 -0
- package/dist/heart/daemon/run-hooks.js +39 -0
- package/dist/heart/daemon/runtime-logging.js +67 -16
- package/dist/heart/daemon/runtime-metadata.js +191 -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 +355 -0
- 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 +307 -0
- package/dist/heart/daemon/stale-bundle-prune.js +96 -0
- package/dist/heart/daemon/startup-tui.js +237 -0
- package/dist/heart/daemon/task-scheduler.js +3 -25
- package/dist/heart/daemon/thoughts.js +510 -0
- package/dist/heart/daemon/up-progress.js +135 -0
- package/dist/heart/delegation.js +62 -0
- package/dist/heart/habits/habit-migration.js +181 -0
- package/dist/heart/habits/habit-parser.js +140 -0
- package/dist/heart/habits/habit-scheduler.js +371 -0
- package/dist/heart/hatch/hatch-animation.js +35 -0
- package/dist/heart/{daemon → hatch}/hatch-flow.js +55 -135
- package/dist/heart/{daemon → hatch}/hatch-specialist.js +3 -3
- package/dist/heart/hatch/specialist-orchestrator.js +129 -0
- package/dist/heart/hatch/specialist-prompt.js +102 -0
- package/dist/heart/hatch/specialist-tools.js +304 -0
- package/dist/heart/identity.js +246 -58
- package/dist/heart/kept-notes.js +357 -0
- package/dist/heart/kicks.js +2 -20
- package/dist/heart/machine-identity.js +161 -0
- package/dist/heart/mcp/mcp-server.js +653 -0
- package/dist/heart/migrate-config.js +100 -0
- package/dist/heart/model-capabilities.js +59 -0
- package/dist/heart/outlook/outlook-http-hooks.js +64 -0
- package/dist/heart/outlook/outlook-http-response.js +7 -0
- package/dist/heart/outlook/outlook-http-routes.js +232 -0
- package/dist/heart/outlook/outlook-http-static.js +99 -0
- package/dist/heart/outlook/outlook-http-transport.js +116 -0
- package/dist/heart/outlook/outlook-http.js +99 -0
- package/dist/heart/outlook/outlook-read.js +28 -0
- package/dist/heart/outlook/outlook-types.js +27 -0
- package/dist/heart/outlook/outlook-view.js +195 -0
- package/dist/heart/outlook/readers/agent-machine.js +359 -0
- package/dist/heart/outlook/readers/continuity-readers.js +332 -0
- package/dist/heart/outlook/readers/runtime-readers.js +660 -0
- package/dist/heart/outlook/readers/sessions.js +232 -0
- package/dist/heart/outlook/readers/shared.js +111 -0
- package/dist/heart/platform.js +81 -0
- package/dist/heart/progress-story.js +42 -0
- package/dist/heart/provider-attempt.js +133 -0
- package/dist/heart/provider-binding-resolver.js +239 -0
- package/dist/heart/provider-credentials.js +383 -0
- package/dist/heart/provider-failover.js +266 -0
- package/dist/heart/provider-models.js +81 -0
- package/dist/heart/provider-ping.js +237 -0
- package/dist/heart/provider-state.js +216 -0
- package/dist/heart/provider-visibility.js +186 -0
- package/dist/heart/providers/anthropic-token.js +131 -0
- package/dist/heart/providers/anthropic.js +202 -50
- package/dist/heart/providers/azure.js +103 -12
- package/dist/heart/providers/error-classification.js +63 -0
- package/dist/heart/providers/github-copilot.js +145 -0
- package/dist/heart/providers/minimax-vlm.js +189 -0
- package/dist/heart/providers/minimax.js +29 -7
- package/dist/heart/providers/openai-codex.js +39 -29
- package/dist/heart/runtime-credentials.js +181 -0
- package/dist/heart/sense-truth.js +61 -0
- package/dist/heart/session-activity.js +190 -0
- package/dist/heart/session-events.js +855 -0
- package/dist/heart/session-transcript.js +167 -0
- package/dist/heart/start-of-turn-packet.js +345 -0
- package/dist/heart/streaming.js +117 -33
- package/dist/heart/sync.js +332 -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-friction.js +55 -0
- package/dist/heart/tool-loop.js +200 -0
- package/dist/heart/turn-context.js +351 -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/versioning/ouro-path-installer.js +301 -0
- package/dist/heart/{daemon → versioning}/ouro-uti.js +11 -2
- package/dist/heart/versioning/ouro-version-manager.js +295 -0
- package/dist/heart/versioning/staged-restart.js +146 -0
- package/dist/heart/versioning/update-checker.js +113 -0
- package/dist/heart/versioning/update-hooks.js +142 -0
- package/dist/heart/versioning/wrapper-publish-guard.js +86 -0
- package/dist/mind/bundle-manifest.js +77 -1
- package/dist/mind/context.js +141 -94
- package/dist/mind/diary-integrity.js +60 -0
- package/dist/mind/{memory.js → diary.js} +84 -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 +64 -0
- package/dist/mind/friends/group-context.js +144 -0
- package/dist/mind/friends/resolver.js +38 -1
- package/dist/mind/friends/store-file.js +58 -3
- package/dist/mind/friends/trust-explanation.js +74 -0
- package/dist/mind/friends/types.js +10 -2
- package/dist/mind/journal-index.js +161 -0
- package/dist/mind/note-search.js +268 -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-refresh.js +3 -2
- package/dist/mind/prompt.js +1111 -117
- package/dist/mind/provenance-trust.js +26 -0
- package/dist/mind/scrutiny.js +173 -0
- package/dist/mind/token-estimate.js +8 -12
- package/dist/nerves/cli-logging.js +22 -3
- package/dist/nerves/coverage/audit-rules.js +15 -6
- package/dist/nerves/coverage/audit.js +28 -2
- package/dist/nerves/coverage/cli.js +1 -1
- package/dist/nerves/coverage/contract.js +5 -5
- package/dist/nerves/coverage/file-completeness.js +83 -5
- package/dist/nerves/coverage/run-artifacts.js +1 -1
- package/dist/nerves/event-buffer.js +111 -0
- package/dist/nerves/index.js +224 -4
- package/dist/nerves/observation.js +20 -0
- package/dist/nerves/redact.js +79 -0
- package/dist/nerves/runtime.js +5 -1
- package/dist/outlook-ui/assets/index-BAcU08c-.css +1 -0
- package/dist/outlook-ui/assets/index-D7l3l4vY.js +61 -0
- package/dist/outlook-ui/index.html +15 -0
- package/dist/repertoire/ado-client.js +17 -56
- package/dist/repertoire/ado-semantic.js +11 -10
- package/dist/repertoire/api-client.js +97 -0
- package/dist/repertoire/bitwarden-store.js +461 -0
- package/dist/repertoire/bundle-templates.js +72 -0
- package/dist/repertoire/bw-installer.js +79 -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 +301 -0
- package/dist/repertoire/coding/index.js +4 -1
- package/dist/repertoire/coding/manager.js +220 -13
- package/dist/repertoire/coding/spawner.js +58 -12
- package/dist/repertoire/coding/tools.js +209 -7
- package/dist/repertoire/commerce-errors.js +109 -0
- package/dist/repertoire/commerce-self-test.js +156 -0
- package/dist/repertoire/credential-access.js +107 -0
- package/dist/repertoire/data/ado-endpoints.json +188 -0
- package/dist/repertoire/duffel-client.js +185 -0
- package/dist/repertoire/github-client.js +14 -55
- package/dist/repertoire/graph-client.js +11 -52
- package/dist/repertoire/guardrails.js +371 -0
- package/dist/repertoire/mcp-client.js +255 -0
- package/dist/repertoire/mcp-manager.js +305 -0
- package/dist/repertoire/mcp-tools.js +63 -0
- package/dist/repertoire/shell-sessions.js +133 -0
- package/dist/repertoire/skills.js +15 -24
- package/dist/repertoire/stripe-client.js +131 -0
- 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 +16 -79
- package/dist/repertoire/tool-results.js +29 -0
- package/dist/repertoire/tools-attachments.js +317 -0
- package/dist/repertoire/tools-base.js +45 -707
- package/dist/repertoire/tools-bluebubbles.js +94 -0
- package/dist/repertoire/tools-bridge.js +141 -0
- package/dist/repertoire/tools-bundle.js +984 -0
- package/dist/repertoire/tools-config.js +185 -0
- package/dist/repertoire/tools-continuity.js +248 -0
- package/dist/repertoire/tools-credential.js +182 -0
- package/dist/repertoire/tools-files.js +342 -0
- package/dist/repertoire/tools-flight.js +224 -0
- package/dist/repertoire/tools-flow.js +105 -0
- package/dist/repertoire/tools-github.js +1 -7
- package/dist/repertoire/tools-notes.js +376 -0
- package/dist/repertoire/tools-session.js +739 -0
- package/dist/repertoire/tools-shell.js +120 -0
- package/dist/repertoire/tools-stripe.js +180 -0
- package/dist/repertoire/tools-surface.js +243 -0
- package/dist/repertoire/tools-teams.js +64 -61
- package/dist/repertoire/tools-travel.js +125 -0
- package/dist/repertoire/tools-user-profile.js +144 -0
- package/dist/repertoire/tools-vault.js +40 -0
- package/dist/repertoire/tools.js +149 -98
- package/dist/repertoire/travel-api-client.js +360 -0
- package/dist/repertoire/user-profile.js +118 -0
- package/dist/repertoire/vault-setup.js +246 -0
- package/dist/repertoire/vault-unlock.js +382 -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 +116 -0
- package/dist/senses/bluebubbles/attachment-cache.js +53 -0
- package/dist/senses/bluebubbles/attachment-download.js +137 -0
- package/dist/senses/bluebubbles/client.js +685 -0
- package/dist/senses/bluebubbles/entry.js +70 -0
- package/dist/senses/bluebubbles/inbound-log.js +113 -0
- package/dist/senses/bluebubbles/index.js +1620 -0
- package/dist/senses/bluebubbles/media.js +389 -0
- package/dist/senses/bluebubbles/model.js +282 -0
- package/dist/senses/bluebubbles/mutation-log.js +116 -0
- package/dist/senses/bluebubbles/replay.js +129 -0
- package/dist/senses/bluebubbles/runtime-state.js +109 -0
- package/dist/senses/bluebubbles/session-cleanup.js +72 -0
- package/dist/senses/cli/bracketed-paste.js +82 -0
- package/dist/senses/cli/image-paste.js +287 -0
- package/dist/senses/cli/image-ref-navigation.js +75 -0
- package/dist/senses/cli/ink-app.js +156 -0
- package/dist/senses/cli/inline-diff.js +64 -0
- package/dist/senses/cli/input-keys.js +174 -0
- package/dist/senses/cli/kill-ring.js +86 -0
- package/dist/senses/cli/message-list.js +51 -0
- package/dist/senses/cli/ouro-tui.js +605 -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 +240 -0
- package/dist/senses/cli/virtual-list.js +35 -0
- package/dist/senses/cli-entry.js +60 -8
- package/dist/senses/cli-layout.js +187 -0
- package/dist/senses/cli.js +768 -264
- package/dist/senses/commands.js +66 -3
- 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 +636 -86
- package/dist/senses/pipeline.js +602 -0
- package/dist/senses/proactive-content-guard.js +51 -0
- package/dist/senses/shared-turn.js +205 -0
- package/dist/senses/surface-tool.js +68 -0
- package/dist/senses/teams-entry.js +60 -8
- package/dist/senses/teams.js +844 -197
- package/dist/senses/trust-gate.js +112 -2
- package/package.json +38 -6
- package/skills/agent-commerce.md +106 -0
- package/skills/browser-navigation.md +110 -0
- package/skills/commerce-setup-guide.md +116 -0
- package/skills/commerce-setup.md +84 -0
- package/skills/configure-dev-tools.md +101 -0
- package/skills/travel-planning.md +134 -0
- package/AdoptionSpecialist.ouro/agent.json +0 -20
- package/AdoptionSpecialist.ouro/psyche/SOUL.md +0 -22
- package/dist/heart/daemon/subagent-installer.js +0 -125
- package/dist/inner-worker-entry.js +0 -4
- package/dist/mind/associative-recall.js +0 -197
- package/subagents/README.md +0 -73
- package/subagents/work-doer.md +0 -233
- package/subagents/work-merger.md +0 -624
- package/subagents/work-planner.md +0 -373
- /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/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-snake.md +0 -0
package/dist/heart/streaming.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.SettleStreamer = exports.SettleParser = void 0;
|
|
4
4
|
exports.toResponsesInput = toResponsesInput;
|
|
5
5
|
exports.toResponsesTools = toResponsesTools;
|
|
6
6
|
exports.streamChatCompletion = streamChatCompletion;
|
|
7
7
|
exports.streamResponsesApi = streamResponsesApi;
|
|
8
8
|
const runtime_1 = require("../nerves/runtime");
|
|
9
9
|
// Character-level state machine that extracts the answer value from
|
|
10
|
-
// `
|
|
10
|
+
// `settle` tool call JSON arguments as they stream in.
|
|
11
11
|
// Scans for prefix `"answer":"` or `"answer": "` in the character stream,
|
|
12
12
|
// then emits text handling JSON escapes, stopping at unescaped closing `"`.
|
|
13
|
-
class
|
|
13
|
+
class SettleParser {
|
|
14
14
|
// Possible prefixes to match (with and without space after colon)
|
|
15
15
|
static PREFIXES = ['"answer":"', '"answer": "'];
|
|
16
16
|
// Buffer of characters seen so far (pre-activation only)
|
|
@@ -29,7 +29,7 @@ class FinalAnswerParser {
|
|
|
29
29
|
if (!this._active) {
|
|
30
30
|
this.buf += ch;
|
|
31
31
|
// Check if any prefix has been fully matched in the buffer
|
|
32
|
-
for (const prefix of
|
|
32
|
+
for (const prefix of SettleParser.PREFIXES) {
|
|
33
33
|
if (this.buf.endsWith(prefix)) {
|
|
34
34
|
this._active = true;
|
|
35
35
|
break;
|
|
@@ -76,7 +76,96 @@ class FinalAnswerParser {
|
|
|
76
76
|
return out;
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
|
-
exports.
|
|
79
|
+
exports.SettleParser = SettleParser;
|
|
80
|
+
// Shared helper: wraps SettleParser with onClearText + onTextChunk wiring.
|
|
81
|
+
// Used by all streaming providers (Chat Completions, Responses API, Anthropic)
|
|
82
|
+
// so the eager-match settle streaming pattern lives in one place.
|
|
83
|
+
class SettleStreamer {
|
|
84
|
+
parser = new SettleParser();
|
|
85
|
+
_detected = false;
|
|
86
|
+
callbacks;
|
|
87
|
+
enabled;
|
|
88
|
+
constructor(callbacks, enabled = true) {
|
|
89
|
+
this.callbacks = callbacks;
|
|
90
|
+
this.enabled = enabled;
|
|
91
|
+
}
|
|
92
|
+
get detected() { return this._detected; }
|
|
93
|
+
get streamed() { return this.parser.active; }
|
|
94
|
+
/** Mark settle as detected. Calls onClearText on the callbacks. */
|
|
95
|
+
activate() {
|
|
96
|
+
if (!this.enabled)
|
|
97
|
+
return;
|
|
98
|
+
if (this._detected)
|
|
99
|
+
return;
|
|
100
|
+
this._detected = true;
|
|
101
|
+
this.callbacks.onClearText?.();
|
|
102
|
+
}
|
|
103
|
+
/** Feed an argument delta through the parser. Emits text via onTextChunk. */
|
|
104
|
+
processDelta(delta) {
|
|
105
|
+
if (!this.enabled)
|
|
106
|
+
return;
|
|
107
|
+
if (!this._detected)
|
|
108
|
+
return;
|
|
109
|
+
const text = this.parser.process(delta);
|
|
110
|
+
if (text)
|
|
111
|
+
this.callbacks.onTextChunk(text);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
exports.SettleStreamer = SettleStreamer;
|
|
115
|
+
function toResponsesUserContent(content) {
|
|
116
|
+
if (typeof content === "string") {
|
|
117
|
+
return content;
|
|
118
|
+
}
|
|
119
|
+
if (!Array.isArray(content)) {
|
|
120
|
+
return "";
|
|
121
|
+
}
|
|
122
|
+
const parts = [];
|
|
123
|
+
for (const part of content) {
|
|
124
|
+
if (!part || typeof part !== "object") {
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if (part.type === "text" && typeof part.text === "string") {
|
|
128
|
+
parts.push({ type: "input_text", text: part.text });
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (part.type === "image_url") {
|
|
132
|
+
const imageUrl = typeof part.image_url?.url === "string" ? part.image_url.url : "";
|
|
133
|
+
if (!imageUrl)
|
|
134
|
+
continue;
|
|
135
|
+
parts.push({
|
|
136
|
+
type: "input_image",
|
|
137
|
+
image_url: imageUrl,
|
|
138
|
+
detail: part.image_url?.detail ?? "auto",
|
|
139
|
+
});
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
if (part.type === "input_audio" &&
|
|
143
|
+
typeof part.input_audio?.data === "string" &&
|
|
144
|
+
(part.input_audio.format === "mp3" || part.input_audio.format === "wav")) {
|
|
145
|
+
parts.push({
|
|
146
|
+
type: "input_audio",
|
|
147
|
+
input_audio: {
|
|
148
|
+
data: part.input_audio.data,
|
|
149
|
+
format: part.input_audio.format,
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
if (part.type === "file") {
|
|
155
|
+
const fileRecord = { type: "input_file" };
|
|
156
|
+
if (typeof part.file?.file_data === "string")
|
|
157
|
+
fileRecord.file_data = part.file.file_data;
|
|
158
|
+
if (typeof part.file?.file_id === "string")
|
|
159
|
+
fileRecord.file_id = part.file.file_id;
|
|
160
|
+
if (typeof part.file?.filename === "string")
|
|
161
|
+
fileRecord.filename = part.file.filename;
|
|
162
|
+
if (typeof part.file?.file_data === "string" || typeof part.file?.file_id === "string") {
|
|
163
|
+
parts.push(fileRecord);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return parts.length > 0 ? parts : "";
|
|
168
|
+
}
|
|
80
169
|
function toResponsesInput(messages) {
|
|
81
170
|
let instructions = "";
|
|
82
171
|
const input = [];
|
|
@@ -90,7 +179,7 @@ function toResponsesInput(messages) {
|
|
|
90
179
|
}
|
|
91
180
|
if (msg.role === "user") {
|
|
92
181
|
const u = msg;
|
|
93
|
-
input.push({ role: "user", content:
|
|
182
|
+
input.push({ role: "user", content: toResponsesUserContent(u.content) });
|
|
94
183
|
continue;
|
|
95
184
|
}
|
|
96
185
|
if (msg.role === "assistant") {
|
|
@@ -102,7 +191,10 @@ function toResponsesInput(messages) {
|
|
|
102
191
|
}
|
|
103
192
|
}
|
|
104
193
|
if (a.content) {
|
|
105
|
-
|
|
194
|
+
const assistantItem = { role: "assistant", content: typeof a.content === "string" ? a.content : "" };
|
|
195
|
+
if (a.phase)
|
|
196
|
+
assistantItem.phase = a.phase;
|
|
197
|
+
input.push(assistantItem);
|
|
106
198
|
}
|
|
107
199
|
if (a.tool_calls) {
|
|
108
200
|
for (const tc of a.tool_calls) {
|
|
@@ -141,7 +233,7 @@ function toResponsesTools(ccTools) {
|
|
|
141
233
|
strict: false,
|
|
142
234
|
}));
|
|
143
235
|
}
|
|
144
|
-
async function streamChatCompletion(client, createParams, callbacks, signal) {
|
|
236
|
+
async function streamChatCompletion(client, createParams, callbacks, signal, eagerSettleStreaming = true) {
|
|
145
237
|
(0, runtime_1.emitNervesEvent)({
|
|
146
238
|
component: "engine",
|
|
147
239
|
event: "engine.stream_start",
|
|
@@ -155,8 +247,7 @@ async function streamChatCompletion(client, createParams, callbacks, signal) {
|
|
|
155
247
|
let toolCalls = {};
|
|
156
248
|
let streamStarted = false;
|
|
157
249
|
let usage;
|
|
158
|
-
const
|
|
159
|
-
let finalAnswerDetected = false;
|
|
250
|
+
const answerStreamer = new SettleStreamer(callbacks, eagerSettleStreaming);
|
|
160
251
|
// State machine for parsing inline <think> tags (MiniMax pattern)
|
|
161
252
|
let contentBuf = "";
|
|
162
253
|
let inThinkTag = false;
|
|
@@ -271,24 +362,21 @@ async function streamChatCompletion(client, createParams, callbacks, signal) {
|
|
|
271
362
|
toolCalls[tc.index].id = tc.id;
|
|
272
363
|
if (tc.function?.name) {
|
|
273
364
|
toolCalls[tc.index].name = tc.function.name;
|
|
274
|
-
// Detect
|
|
365
|
+
// Detect settle tool call on first name delta.
|
|
275
366
|
// Only activate streaming if this is the sole tool call (index 0
|
|
276
367
|
// and no other indices seen). Mixed calls are rejected by core.ts.
|
|
277
|
-
if (tc.function.name === "
|
|
368
|
+
if (tc.function.name === "settle" && !answerStreamer.detected
|
|
278
369
|
&& tc.index === 0 && Object.keys(toolCalls).length === 1) {
|
|
279
|
-
|
|
280
|
-
callbacks.onClearText?.();
|
|
370
|
+
answerStreamer.activate();
|
|
281
371
|
}
|
|
282
372
|
}
|
|
283
373
|
if (tc.function?.arguments) {
|
|
284
374
|
toolCalls[tc.index].arguments += tc.function.arguments;
|
|
285
|
-
// Feed
|
|
375
|
+
// Feed settle argument deltas to the parser for progressive
|
|
286
376
|
// streaming, but only when it appears to be the sole tool call.
|
|
287
|
-
if (
|
|
377
|
+
if (answerStreamer.detected && toolCalls[tc.index].name === "settle"
|
|
288
378
|
&& Object.keys(toolCalls).length === 1) {
|
|
289
|
-
|
|
290
|
-
if (text)
|
|
291
|
-
callbacks.onTextChunk(text);
|
|
379
|
+
answerStreamer.processDelta(tc.function.arguments);
|
|
292
380
|
}
|
|
293
381
|
}
|
|
294
382
|
}
|
|
@@ -302,10 +390,10 @@ async function streamChatCompletion(client, createParams, callbacks, signal) {
|
|
|
302
390
|
toolCalls: Object.values(toolCalls),
|
|
303
391
|
outputItems: [],
|
|
304
392
|
usage,
|
|
305
|
-
|
|
393
|
+
settleStreamed: answerStreamer.streamed,
|
|
306
394
|
};
|
|
307
395
|
}
|
|
308
|
-
async function streamResponsesApi(client, createParams, callbacks, signal) {
|
|
396
|
+
async function streamResponsesApi(client, createParams, callbacks, signal, eagerSettleStreaming = true) {
|
|
309
397
|
(0, runtime_1.emitNervesEvent)({
|
|
310
398
|
component: "engine",
|
|
311
399
|
event: "engine.stream_start",
|
|
@@ -320,9 +408,8 @@ async function streamResponsesApi(client, createParams, callbacks, signal) {
|
|
|
320
408
|
const outputItems = [];
|
|
321
409
|
let currentToolCall = null;
|
|
322
410
|
let usage;
|
|
323
|
-
const
|
|
411
|
+
const answerStreamer = new SettleStreamer(callbacks, eagerSettleStreaming);
|
|
324
412
|
let functionCallCount = 0;
|
|
325
|
-
let finalAnswerDetected = false;
|
|
326
413
|
for await (const event of response) {
|
|
327
414
|
if (signal?.aborted)
|
|
328
415
|
break;
|
|
@@ -351,12 +438,11 @@ async function streamResponsesApi(client, createParams, callbacks, signal) {
|
|
|
351
438
|
name: String(event.item.name),
|
|
352
439
|
arguments: "",
|
|
353
440
|
};
|
|
354
|
-
// Detect
|
|
441
|
+
// Detect settle function call -- clear any streamed noise.
|
|
355
442
|
// Only activate when this is the first (and so far only) function call.
|
|
356
443
|
// Mixed calls are rejected by core.ts; no need to stream their args.
|
|
357
|
-
if (String(event.item.name) === "
|
|
358
|
-
|
|
359
|
-
callbacks.onClearText?.();
|
|
444
|
+
if (String(event.item.name) === "settle" && functionCallCount === 1) {
|
|
445
|
+
answerStreamer.activate();
|
|
360
446
|
}
|
|
361
447
|
}
|
|
362
448
|
break;
|
|
@@ -364,13 +450,11 @@ async function streamResponsesApi(client, createParams, callbacks, signal) {
|
|
|
364
450
|
case "response.function_call_arguments.delta": {
|
|
365
451
|
if (currentToolCall) {
|
|
366
452
|
currentToolCall.arguments += event.delta;
|
|
367
|
-
// Feed
|
|
453
|
+
// Feed settle argument deltas to the parser for progressive
|
|
368
454
|
// streaming, but only when it appears to be the sole function call.
|
|
369
|
-
if (
|
|
455
|
+
if (answerStreamer.detected && currentToolCall.name === "settle"
|
|
370
456
|
&& functionCallCount === 1) {
|
|
371
|
-
|
|
372
|
-
if (text)
|
|
373
|
-
callbacks.onTextChunk(text);
|
|
457
|
+
answerStreamer.processDelta(String(event.delta));
|
|
374
458
|
}
|
|
375
459
|
}
|
|
376
460
|
break;
|
|
@@ -410,6 +494,6 @@ async function streamResponsesApi(client, createParams, callbacks, signal) {
|
|
|
410
494
|
toolCalls,
|
|
411
495
|
outputItems,
|
|
412
496
|
usage,
|
|
413
|
-
|
|
497
|
+
settleStreamed: answerStreamer.streamed,
|
|
414
498
|
};
|
|
415
499
|
}
|
|
@@ -0,0 +1,332 @@
|
|
|
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.preTurnPull = preTurnPull;
|
|
37
|
+
exports.postTurnPush = postTurnPush;
|
|
38
|
+
const child_process_1 = require("child_process");
|
|
39
|
+
const fs = __importStar(require("fs"));
|
|
40
|
+
const path = __importStar(require("path"));
|
|
41
|
+
const runtime_1 = require("../nerves/runtime");
|
|
42
|
+
function writePendingSync(agentRoot, error, classification, conflictFiles) {
|
|
43
|
+
const pendingSyncPath = path.join(agentRoot, "state", "pending-sync.json");
|
|
44
|
+
fs.mkdirSync(path.join(agentRoot, "state"), { recursive: true });
|
|
45
|
+
const record = {
|
|
46
|
+
error,
|
|
47
|
+
failedAt: new Date().toISOString(),
|
|
48
|
+
classification,
|
|
49
|
+
conflictFiles,
|
|
50
|
+
};
|
|
51
|
+
fs.writeFileSync(pendingSyncPath, JSON.stringify(record, null, 2), "utf-8");
|
|
52
|
+
}
|
|
53
|
+
function collectRebaseConflictFiles(agentRoot) {
|
|
54
|
+
try {
|
|
55
|
+
const output = (0, child_process_1.execFileSync)("git", ["status", "--porcelain=v1"], {
|
|
56
|
+
cwd: agentRoot,
|
|
57
|
+
stdio: "pipe",
|
|
58
|
+
timeout: 5000,
|
|
59
|
+
}).toString();
|
|
60
|
+
const files = [];
|
|
61
|
+
for (const line of output.split("\n")) {
|
|
62
|
+
// Unmerged paths in porcelain v1 are prefixed with UU/AA/DD/AU/UA/DU/UD
|
|
63
|
+
if (/^(UU|AA|DD|AU|UA|DU|UD) /.test(line)) {
|
|
64
|
+
files.push(line.slice(3).trim());
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return files;
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
/* v8 ignore next -- git status --porcelain failure inside a repo would require a corrupt repo @preserve */
|
|
71
|
+
return [];
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Check whether the bundle is initialized as a git repo.
|
|
76
|
+
* Used by both pre-turn pull and post-turn push to surface a clear,
|
|
77
|
+
* actionable error when sync is enabled but the user never ran `git init`
|
|
78
|
+
* inside their bundle. This error is propagated all the way into the
|
|
79
|
+
* agent's start-of-turn packet as a Sync warning, so the agent can
|
|
80
|
+
* either ask the user or run `git init` itself.
|
|
81
|
+
*/
|
|
82
|
+
function ensureGitRepo(agentRoot) {
|
|
83
|
+
if (fs.existsSync(path.join(agentRoot, ".git"))) {
|
|
84
|
+
return { ok: true };
|
|
85
|
+
}
|
|
86
|
+
const error = `bundle is not a git repo; run \`git init\` inside ${agentRoot} to enable sync (or disable sync in agent.json)`;
|
|
87
|
+
return { ok: false, error };
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Pre-turn pull: sync the agent bundle from remote before assembling the start-of-turn packet.
|
|
91
|
+
*
|
|
92
|
+
* If the bundle has no git remote configured, the pull is skipped and the function
|
|
93
|
+
* returns ok — matching the no-remote behavior of postTurnPush. This supports the
|
|
94
|
+
* "local-only sync" mode where the bundle accumulates a commit log without ever
|
|
95
|
+
* pushing or pulling from a remote.
|
|
96
|
+
*/
|
|
97
|
+
function preTurnPull(agentRoot, config) {
|
|
98
|
+
(0, runtime_1.emitNervesEvent)({
|
|
99
|
+
component: "heart",
|
|
100
|
+
event: "heart.sync_pull_start",
|
|
101
|
+
message: "pre-turn pull starting",
|
|
102
|
+
meta: { agentRoot, remote: config.remote },
|
|
103
|
+
});
|
|
104
|
+
// Check that the bundle is actually a git repo before touching git at all.
|
|
105
|
+
// Surfaces a clear, actionable error via syncFailure → start-of-turn packet
|
|
106
|
+
// so the agent can propose running `git init` (or just do it).
|
|
107
|
+
const repoCheck = ensureGitRepo(agentRoot);
|
|
108
|
+
if (!repoCheck.ok) {
|
|
109
|
+
(0, runtime_1.emitNervesEvent)({
|
|
110
|
+
level: "warn",
|
|
111
|
+
component: "heart",
|
|
112
|
+
event: "heart.sync_not_a_repo",
|
|
113
|
+
message: "pre-turn pull failed: bundle is not a git repo",
|
|
114
|
+
meta: { agentRoot },
|
|
115
|
+
});
|
|
116
|
+
return repoCheck;
|
|
117
|
+
}
|
|
118
|
+
// Check if any remote is configured. If not, skip the pull (local-only mode).
|
|
119
|
+
try {
|
|
120
|
+
const remoteOutput = (0, child_process_1.execFileSync)("git", ["remote"], {
|
|
121
|
+
cwd: agentRoot,
|
|
122
|
+
stdio: "pipe",
|
|
123
|
+
timeout: 5000,
|
|
124
|
+
}).toString().trim();
|
|
125
|
+
if (remoteOutput.length === 0) {
|
|
126
|
+
(0, runtime_1.emitNervesEvent)({
|
|
127
|
+
component: "heart",
|
|
128
|
+
event: "heart.sync_pull_end",
|
|
129
|
+
message: "pre-turn pull skipped: no remote configured",
|
|
130
|
+
meta: { agentRoot },
|
|
131
|
+
});
|
|
132
|
+
return { ok: true };
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
catch (err) {
|
|
136
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
137
|
+
(0, runtime_1.emitNervesEvent)({
|
|
138
|
+
component: "heart",
|
|
139
|
+
event: "heart.sync_pull_error",
|
|
140
|
+
message: "pre-turn pull failed: git remote check failed",
|
|
141
|
+
meta: { agentRoot, error },
|
|
142
|
+
});
|
|
143
|
+
return { ok: false, error };
|
|
144
|
+
}
|
|
145
|
+
try {
|
|
146
|
+
(0, child_process_1.execFileSync)("git", ["pull", config.remote], {
|
|
147
|
+
cwd: agentRoot,
|
|
148
|
+
stdio: "pipe",
|
|
149
|
+
timeout: 30000,
|
|
150
|
+
});
|
|
151
|
+
(0, runtime_1.emitNervesEvent)({
|
|
152
|
+
component: "heart",
|
|
153
|
+
event: "heart.sync_pull_end",
|
|
154
|
+
message: "pre-turn pull complete",
|
|
155
|
+
meta: { agentRoot },
|
|
156
|
+
});
|
|
157
|
+
return { ok: true };
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
161
|
+
(0, runtime_1.emitNervesEvent)({
|
|
162
|
+
component: "heart",
|
|
163
|
+
event: "heart.sync_pull_error",
|
|
164
|
+
message: "pre-turn pull failed",
|
|
165
|
+
meta: { agentRoot, error },
|
|
166
|
+
});
|
|
167
|
+
return { ok: false, error };
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Post-turn push: discover dirty files via `git status`, commit, and push.
|
|
172
|
+
* Uses git-status-based discovery instead of explicit path tracking, ensuring
|
|
173
|
+
* all file writers are captured regardless of whether they call a tracking API.
|
|
174
|
+
*/
|
|
175
|
+
function postTurnPush(agentRoot, config) {
|
|
176
|
+
(0, runtime_1.emitNervesEvent)({
|
|
177
|
+
component: "heart",
|
|
178
|
+
event: "heart.sync_push_start",
|
|
179
|
+
message: "post-turn push starting",
|
|
180
|
+
meta: { agentRoot, remote: config.remote },
|
|
181
|
+
});
|
|
182
|
+
// Same git-repo check as preTurnPull. This is the more common failure path
|
|
183
|
+
// since postTurnPush runs after every turn while preTurnPull only runs on
|
|
184
|
+
// user-initiated turns. Prior to this guard, an un-init'd bundle would fail
|
|
185
|
+
// the git-status invocation below with a generic "not a git repository"
|
|
186
|
+
// error; now we catch it explicitly with an actionable message.
|
|
187
|
+
const repoCheck = ensureGitRepo(agentRoot);
|
|
188
|
+
if (!repoCheck.ok) {
|
|
189
|
+
(0, runtime_1.emitNervesEvent)({
|
|
190
|
+
level: "warn",
|
|
191
|
+
component: "heart",
|
|
192
|
+
event: "heart.sync_not_a_repo",
|
|
193
|
+
message: "post-turn push failed: bundle is not a git repo",
|
|
194
|
+
meta: { agentRoot },
|
|
195
|
+
});
|
|
196
|
+
return repoCheck;
|
|
197
|
+
}
|
|
198
|
+
let statusOutput;
|
|
199
|
+
try {
|
|
200
|
+
statusOutput = (0, child_process_1.execFileSync)("git", ["status", "--porcelain"], {
|
|
201
|
+
cwd: agentRoot,
|
|
202
|
+
stdio: "pipe",
|
|
203
|
+
timeout: 10000,
|
|
204
|
+
}).toString().trim();
|
|
205
|
+
}
|
|
206
|
+
catch (err) {
|
|
207
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
208
|
+
(0, runtime_1.emitNervesEvent)({
|
|
209
|
+
component: "heart",
|
|
210
|
+
event: "heart.sync_push_error",
|
|
211
|
+
message: "post-turn push: git status failed",
|
|
212
|
+
meta: { agentRoot, error },
|
|
213
|
+
});
|
|
214
|
+
return { ok: false, error };
|
|
215
|
+
}
|
|
216
|
+
if (statusOutput.length === 0) {
|
|
217
|
+
(0, runtime_1.emitNervesEvent)({
|
|
218
|
+
component: "heart",
|
|
219
|
+
event: "heart.sync_push_end",
|
|
220
|
+
message: "post-turn push: no changes to sync",
|
|
221
|
+
meta: { agentRoot },
|
|
222
|
+
});
|
|
223
|
+
return { ok: true };
|
|
224
|
+
}
|
|
225
|
+
const changedCount = statusOutput.split("\n").length;
|
|
226
|
+
try {
|
|
227
|
+
(0, child_process_1.execFileSync)("git", ["add", "-A"], {
|
|
228
|
+
cwd: agentRoot,
|
|
229
|
+
stdio: "pipe",
|
|
230
|
+
timeout: 10000,
|
|
231
|
+
});
|
|
232
|
+
(0, child_process_1.execFileSync)("git", ["commit", "-m", "sync: post-turn update"], {
|
|
233
|
+
cwd: agentRoot,
|
|
234
|
+
stdio: "pipe",
|
|
235
|
+
timeout: 10000,
|
|
236
|
+
});
|
|
237
|
+
// Check if a remote exists
|
|
238
|
+
const remoteOutput = (0, child_process_1.execFileSync)("git", ["remote"], {
|
|
239
|
+
cwd: agentRoot,
|
|
240
|
+
stdio: "pipe",
|
|
241
|
+
timeout: 5000,
|
|
242
|
+
}).toString().trim();
|
|
243
|
+
if (remoteOutput.length === 0) {
|
|
244
|
+
(0, runtime_1.emitNervesEvent)({
|
|
245
|
+
component: "heart",
|
|
246
|
+
event: "heart.sync_push_end",
|
|
247
|
+
message: "post-turn push: committed locally, no remote configured",
|
|
248
|
+
meta: { agentRoot, changedCount },
|
|
249
|
+
});
|
|
250
|
+
return { ok: true };
|
|
251
|
+
}
|
|
252
|
+
try {
|
|
253
|
+
(0, child_process_1.execFileSync)("git", ["push", config.remote], {
|
|
254
|
+
cwd: agentRoot,
|
|
255
|
+
stdio: "pipe",
|
|
256
|
+
timeout: 30000,
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
catch {
|
|
260
|
+
// Push rejected -- try pull-rebase-push
|
|
261
|
+
let rebaseError = null;
|
|
262
|
+
try {
|
|
263
|
+
(0, child_process_1.execFileSync)("git", ["pull", "--rebase", config.remote], {
|
|
264
|
+
cwd: agentRoot,
|
|
265
|
+
stdio: "pipe",
|
|
266
|
+
timeout: 30000,
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
catch (err) {
|
|
270
|
+
rebaseError = err instanceof Error ? err.message : String(err);
|
|
271
|
+
}
|
|
272
|
+
if (rebaseError === null) {
|
|
273
|
+
try {
|
|
274
|
+
(0, child_process_1.execFileSync)("git", ["push", config.remote], {
|
|
275
|
+
cwd: agentRoot,
|
|
276
|
+
stdio: "pipe",
|
|
277
|
+
timeout: 30000,
|
|
278
|
+
});
|
|
279
|
+
// rebase + retry push both succeeded — fall through to success
|
|
280
|
+
(0, runtime_1.emitNervesEvent)({
|
|
281
|
+
component: "heart",
|
|
282
|
+
event: "heart.sync_push_end",
|
|
283
|
+
message: "post-turn push complete after rebase retry",
|
|
284
|
+
meta: { agentRoot, changedCount },
|
|
285
|
+
});
|
|
286
|
+
return { ok: true };
|
|
287
|
+
}
|
|
288
|
+
catch (retryErr) {
|
|
289
|
+
// Second push rejected — remote advanced again during rebase
|
|
290
|
+
const retryError = retryErr instanceof Error ? retryErr.message : /* v8 ignore next -- defensive non-Error catch @preserve */ String(retryErr);
|
|
291
|
+
writePendingSync(agentRoot, retryError, "push_rejected", []);
|
|
292
|
+
(0, runtime_1.emitNervesEvent)({
|
|
293
|
+
component: "heart",
|
|
294
|
+
event: "heart.sync_push_error",
|
|
295
|
+
message: "post-turn push failed after retry: push_rejected",
|
|
296
|
+
meta: { agentRoot, error: retryError, classification: "push_rejected" },
|
|
297
|
+
});
|
|
298
|
+
return { ok: false, error: retryError };
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
// Rebase failed — detect conflict files via git status. Preserve
|
|
302
|
+
// the original rebase error message so callers see the real cause.
|
|
303
|
+
const conflictFiles = collectRebaseConflictFiles(agentRoot);
|
|
304
|
+
const classification = conflictFiles.length > 0 ? "pull_rebase_conflict" : "unknown";
|
|
305
|
+
writePendingSync(agentRoot, rebaseError, classification, conflictFiles);
|
|
306
|
+
(0, runtime_1.emitNervesEvent)({
|
|
307
|
+
component: "heart",
|
|
308
|
+
event: "heart.sync_push_error",
|
|
309
|
+
message: `post-turn push failed: ${classification}`,
|
|
310
|
+
meta: { agentRoot, error: rebaseError, classification, conflictFiles },
|
|
311
|
+
});
|
|
312
|
+
return { ok: false, error: rebaseError };
|
|
313
|
+
}
|
|
314
|
+
(0, runtime_1.emitNervesEvent)({
|
|
315
|
+
component: "heart",
|
|
316
|
+
event: "heart.sync_push_end",
|
|
317
|
+
message: "post-turn push complete",
|
|
318
|
+
meta: { agentRoot, changedCount },
|
|
319
|
+
});
|
|
320
|
+
return { ok: true };
|
|
321
|
+
}
|
|
322
|
+
catch (err) {
|
|
323
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
324
|
+
(0, runtime_1.emitNervesEvent)({
|
|
325
|
+
component: "heart",
|
|
326
|
+
event: "heart.sync_push_error",
|
|
327
|
+
message: "post-turn push failed",
|
|
328
|
+
meta: { agentRoot, error },
|
|
329
|
+
});
|
|
330
|
+
return { ok: false, error };
|
|
331
|
+
}
|
|
332
|
+
}
|