@ouro.bot/cli 0.1.0-alpha.48 → 0.1.0-alpha.480
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 +132 -19
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/agent.json +3 -2
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +2 -2
- package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +1 -1
- package/changelog.json +3061 -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 +857 -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 +426 -0
- package/dist/heart/background-operations.js +234 -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 +110 -128
- package/dist/heart/core.js +745 -227
- package/dist/heart/cross-chat-delivery.js +131 -0
- package/dist/heart/daemon/agent-config-check.js +490 -0
- package/dist/heart/daemon/agent-discovery.js +79 -3
- package/dist/heart/daemon/agent-service.js +360 -0
- package/dist/heart/daemon/agentic-repair.js +216 -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 +640 -0
- package/dist/heart/daemon/cli-exec.js +6933 -0
- package/dist/heart/daemon/cli-help.js +487 -0
- package/dist/heart/daemon/cli-parse.js +1527 -0
- package/dist/heart/daemon/cli-render-doctor.js +57 -0
- package/dist/heart/daemon/cli-render.js +561 -0
- package/dist/heart/daemon/cli-types.js +8 -0
- package/dist/heart/daemon/connect-bay.js +323 -0
- package/dist/heart/daemon/daemon-cli.js +29 -1616
- package/dist/heart/daemon/daemon-entry.js +345 -3
- package/dist/heart/daemon/daemon-health.js +141 -0
- package/dist/heart/daemon/daemon-runtime-sync.js +190 -12
- package/dist/heart/daemon/daemon-tombstone.js +236 -0
- package/dist/heart/daemon/daemon.js +677 -58
- package/dist/heart/daemon/dns-workflow.js +394 -0
- package/dist/heart/daemon/doctor-types.js +8 -0
- package/dist/heart/daemon/doctor.js +486 -0
- package/dist/heart/daemon/health-monitor.js +92 -1
- 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/http-health-probe.js +80 -0
- package/dist/heart/daemon/human-command-screens.js +234 -0
- package/dist/heart/daemon/human-readiness.js +114 -0
- package/dist/heart/daemon/inner-status.js +89 -0
- package/dist/heart/daemon/interactive-repair.js +394 -0
- package/dist/heart/daemon/launchd.js +25 -5
- package/dist/heart/daemon/log-tailer.js +82 -12
- package/dist/heart/daemon/logs-prune.js +110 -0
- package/dist/heart/daemon/message-router.js +2 -2
- 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 +214 -0
- package/dist/heart/daemon/provider-discovery.js +137 -0
- package/dist/heart/daemon/provider-ping-progress.js +83 -0
- package/dist/heart/daemon/pulse.js +475 -0
- package/dist/heart/daemon/readiness-repair.js +365 -0
- package/dist/heart/daemon/run-hooks.js +2 -0
- package/dist/heart/daemon/runtime-logging.js +67 -16
- package/dist/heart/daemon/runtime-metadata.js +73 -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 +178 -37
- 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 +109 -4
- package/dist/heart/daemon/stale-bundle-prune.js +96 -0
- package/dist/heart/daemon/startup-tui.js +264 -0
- package/dist/heart/daemon/task-scheduler.js +3 -25
- package/dist/heart/daemon/terminal-ui.js +499 -0
- package/dist/heart/daemon/thoughts.js +149 -10
- package/dist/heart/daemon/up-progress.js +366 -0
- package/dist/heart/daemon/vault-items.js +56 -0
- package/dist/heart/delegation.js +62 -0
- package/dist/heart/habits/habit-migration.js +189 -0
- package/dist/heart/habits/habit-parser.js +140 -0
- package/dist/heart/habits/habit-runtime-state.js +100 -0
- package/dist/heart/habits/habit-scheduler.js +372 -0
- package/dist/heart/{daemon → hatch}/hatch-flow.js +52 -117
- package/dist/heart/{daemon → hatch}/hatch-specialist.js +3 -3
- package/dist/heart/{daemon → hatch}/specialist-prompt.js +12 -9
- package/dist/heart/{daemon → hatch}/specialist-tools.js +35 -12
- package/dist/heart/identity.js +201 -66
- package/dist/heart/kept-notes.js +357 -0
- package/dist/heart/kicks.js +1 -1
- 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 +66 -0
- package/dist/heart/outlook/outlook-http-response.js +7 -0
- package/dist/heart/outlook/outlook-http-routes.js +244 -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 +31 -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/mail.js +362 -0
- package/dist/heart/outlook/readers/runtime-readers.js +644 -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 +134 -0
- package/dist/heart/provider-binding-resolver.js +255 -0
- package/dist/heart/provider-credentials.js +424 -0
- package/dist/heart/provider-failover.js +266 -0
- package/dist/heart/provider-models.js +81 -0
- package/dist/heart/provider-ping.js +262 -0
- package/dist/heart/provider-state.js +216 -0
- package/dist/heart/provider-visibility.js +188 -0
- package/dist/heart/providers/anthropic-token.js +131 -0
- package/dist/heart/providers/anthropic.js +193 -55
- 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 +62 -38
- package/dist/heart/runtime-capability-check.js +170 -0
- package/dist/heart/runtime-credentials.js +260 -0
- package/dist/heart/sense-truth.js +11 -4
- 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 +36 -27
- 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 +361 -0
- package/dist/heart/turn-coordinator.js +24 -1
- package/dist/heart/{daemon → versioning}/ouro-bot-global-installer.js +1 -1
- package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
- package/dist/heart/versioning/ouro-path-installer.js +425 -0
- package/dist/heart/versioning/ouro-version-manager.js +295 -0
- package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
- package/dist/heart/{daemon → versioning}/update-checker.js +5 -1
- package/dist/heart/{daemon → versioning}/update-hooks.js +63 -59
- package/dist/mailroom/attention.js +167 -0
- package/dist/mailroom/autonomy.js +209 -0
- package/dist/mailroom/blob-store.js +558 -0
- package/dist/mailroom/core.js +658 -0
- package/dist/mailroom/entry.js +160 -0
- package/dist/mailroom/file-store.js +400 -0
- package/dist/mailroom/mbox-import.js +341 -0
- package/dist/mailroom/outbound.js +380 -0
- package/dist/mailroom/policy.js +263 -0
- package/dist/mailroom/reader.js +197 -0
- package/dist/mailroom/smtp-ingress.js +176 -0
- package/dist/mailroom/source-state.js +176 -0
- package/dist/mailroom/travel-extract.js +89 -0
- package/dist/mind/bundle-manifest.js +7 -1
- package/dist/mind/context.js +132 -93
- package/dist/mind/diary-integrity.js +60 -0
- package/dist/mind/{memory.js → diary.js} +74 -93
- package/dist/mind/embedding-provider.js +60 -0
- package/dist/mind/file-state.js +179 -0
- package/dist/mind/friends/channel.js +30 -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 +39 -3
- package/dist/mind/friends/trust-explanation.js +74 -0
- package/dist/mind/friends/types.js +2 -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 +66 -7
- package/dist/mind/prompt-refresh.js +3 -2
- package/dist/mind/prompt.js +978 -169
- package/dist/mind/provenance-trust.js +26 -0
- package/dist/mind/scrutiny.js +173 -0
- package/dist/nerves/cli-logging.js +7 -1
- 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 +84 -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-BPr5vNuM.css +1 -0
- package/dist/outlook-ui/assets/index-CPfhbn13.js +61 -0
- package/dist/outlook-ui/index.html +15 -0
- package/dist/repertoire/ado-client.js +15 -56
- package/dist/repertoire/ado-semantic.js +11 -10
- package/dist/repertoire/api-client.js +97 -0
- package/dist/repertoire/bitwarden-store.js +774 -0
- package/dist/repertoire/bundle-templates.js +72 -0
- package/dist/repertoire/bw-installer.js +180 -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 +158 -9
- package/dist/repertoire/coding/spawner.js +55 -9
- package/dist/repertoire/coding/tools.js +170 -7
- package/dist/repertoire/commerce-errors.js +109 -0
- package/dist/repertoire/commerce-self-test.js +156 -0
- package/dist/repertoire/credential-access.js +111 -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 +396 -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 +37 -4
- 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 -78
- package/dist/repertoire/tool-results.js +29 -0
- package/dist/repertoire/tools-attachments.js +317 -0
- package/dist/repertoire/tools-base.js +44 -740
- package/dist/repertoire/tools-bluebubbles.js +1 -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 +381 -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-mail.js +896 -0
- package/dist/repertoire/tools-notes.js +376 -0
- package/dist/repertoire/tools-session.js +746 -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 +9 -39
- 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 +144 -113
- package/dist/repertoire/travel-api-client.js +360 -0
- package/dist/repertoire/user-profile.js +131 -0
- package/dist/repertoire/vault-setup.js +246 -0
- package/dist/repertoire/vault-unlock.js +561 -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 → bluebubbles/client.js} +219 -18
- package/dist/senses/bluebubbles/entry.js +73 -0
- package/dist/senses/{bluebubbles-inbound-log.js → bluebubbles/inbound-log.js} +7 -3
- package/dist/senses/{bluebubbles.js → bluebubbles/index.js} +705 -116
- package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +121 -70
- package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +33 -12
- package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +3 -3
- package/dist/senses/bluebubbles/replay.js +129 -0
- package/dist/senses/{bluebubbles-runtime-state.js → bluebubbles/runtime-state.js} +2 -2
- package/dist/senses/{bluebubbles-session-cleanup.js → bluebubbles/session-cleanup.js} +1 -1
- 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 +516 -211
- package/dist/senses/commands.js +66 -3
- package/dist/senses/habit-turn-message.js +108 -0
- package/dist/senses/inner-dialog-worker.js +97 -17
- package/dist/senses/inner-dialog.js +404 -14
- package/dist/senses/mail-entry.js +66 -0
- package/dist/senses/mail.js +232 -0
- package/dist/senses/pipeline.js +533 -72
- 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 +413 -163
- package/dist/senses/trust-gate.js +5 -5
- package/package.json +37 -7
- package/skills/agent-commerce.md +106 -0
- package/skills/browser-navigation.md +117 -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 +138 -0
- package/dist/heart/daemon/ouro-path-installer.js +0 -178
- package/dist/heart/daemon/subagent-installer.js +0 -166
- package/dist/mind/associative-recall.js +0 -209
- package/dist/senses/bluebubbles-entry.js +0 -13
- package/dist/senses/debug-activity.js +0 -127
- package/subagents/README.md +0 -86
- package/subagents/work-doer.md +0 -237
- package/subagents/work-merger.md +0 -618
- package/subagents/work-planner.md +0 -390
- /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-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
- /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +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,21 +76,25 @@ class FinalAnswerParser {
|
|
|
76
76
|
return out;
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
|
-
exports.
|
|
80
|
-
// Shared helper: wraps
|
|
79
|
+
exports.SettleParser = SettleParser;
|
|
80
|
+
// Shared helper: wraps SettleParser with onClearText + onTextChunk wiring.
|
|
81
81
|
// Used by all streaming providers (Chat Completions, Responses API, Anthropic)
|
|
82
|
-
// so the eager-match streaming pattern lives in one place.
|
|
83
|
-
class
|
|
84
|
-
parser = new
|
|
82
|
+
// so the eager-match settle streaming pattern lives in one place.
|
|
83
|
+
class SettleStreamer {
|
|
84
|
+
parser = new SettleParser();
|
|
85
85
|
_detected = false;
|
|
86
86
|
callbacks;
|
|
87
|
-
|
|
87
|
+
enabled;
|
|
88
|
+
constructor(callbacks, enabled = true) {
|
|
88
89
|
this.callbacks = callbacks;
|
|
90
|
+
this.enabled = enabled;
|
|
89
91
|
}
|
|
90
92
|
get detected() { return this._detected; }
|
|
91
93
|
get streamed() { return this.parser.active; }
|
|
92
|
-
/** Mark
|
|
94
|
+
/** Mark settle as detected. Calls onClearText on the callbacks. */
|
|
93
95
|
activate() {
|
|
96
|
+
if (!this.enabled)
|
|
97
|
+
return;
|
|
94
98
|
if (this._detected)
|
|
95
99
|
return;
|
|
96
100
|
this._detected = true;
|
|
@@ -98,6 +102,8 @@ class FinalAnswerStreamer {
|
|
|
98
102
|
}
|
|
99
103
|
/** Feed an argument delta through the parser. Emits text via onTextChunk. */
|
|
100
104
|
processDelta(delta) {
|
|
105
|
+
if (!this.enabled)
|
|
106
|
+
return;
|
|
101
107
|
if (!this._detected)
|
|
102
108
|
return;
|
|
103
109
|
const text = this.parser.process(delta);
|
|
@@ -105,7 +111,7 @@ class FinalAnswerStreamer {
|
|
|
105
111
|
this.callbacks.onTextChunk(text);
|
|
106
112
|
}
|
|
107
113
|
}
|
|
108
|
-
exports.
|
|
114
|
+
exports.SettleStreamer = SettleStreamer;
|
|
109
115
|
function toResponsesUserContent(content) {
|
|
110
116
|
if (typeof content === "string") {
|
|
111
117
|
return content;
|
|
@@ -185,7 +191,10 @@ function toResponsesInput(messages) {
|
|
|
185
191
|
}
|
|
186
192
|
}
|
|
187
193
|
if (a.content) {
|
|
188
|
-
|
|
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);
|
|
189
198
|
}
|
|
190
199
|
if (a.tool_calls) {
|
|
191
200
|
for (const tc of a.tool_calls) {
|
|
@@ -224,7 +233,7 @@ function toResponsesTools(ccTools) {
|
|
|
224
233
|
strict: false,
|
|
225
234
|
}));
|
|
226
235
|
}
|
|
227
|
-
async function streamChatCompletion(client, createParams, callbacks, signal) {
|
|
236
|
+
async function streamChatCompletion(client, createParams, callbacks, signal, eagerSettleStreaming = true) {
|
|
228
237
|
(0, runtime_1.emitNervesEvent)({
|
|
229
238
|
component: "engine",
|
|
230
239
|
event: "engine.stream_start",
|
|
@@ -238,7 +247,7 @@ async function streamChatCompletion(client, createParams, callbacks, signal) {
|
|
|
238
247
|
let toolCalls = {};
|
|
239
248
|
let streamStarted = false;
|
|
240
249
|
let usage;
|
|
241
|
-
const answerStreamer = new
|
|
250
|
+
const answerStreamer = new SettleStreamer(callbacks, eagerSettleStreaming);
|
|
242
251
|
// State machine for parsing inline <think> tags (MiniMax pattern)
|
|
243
252
|
let contentBuf = "";
|
|
244
253
|
let inThinkTag = false;
|
|
@@ -353,19 +362,19 @@ async function streamChatCompletion(client, createParams, callbacks, signal) {
|
|
|
353
362
|
toolCalls[tc.index].id = tc.id;
|
|
354
363
|
if (tc.function?.name) {
|
|
355
364
|
toolCalls[tc.index].name = tc.function.name;
|
|
356
|
-
// Detect
|
|
365
|
+
// Detect settle tool call on first name delta.
|
|
357
366
|
// Only activate streaming if this is the sole tool call (index 0
|
|
358
367
|
// and no other indices seen). Mixed calls are rejected by core.ts.
|
|
359
|
-
if (tc.function.name === "
|
|
368
|
+
if (tc.function.name === "settle" && !answerStreamer.detected
|
|
360
369
|
&& tc.index === 0 && Object.keys(toolCalls).length === 1) {
|
|
361
370
|
answerStreamer.activate();
|
|
362
371
|
}
|
|
363
372
|
}
|
|
364
373
|
if (tc.function?.arguments) {
|
|
365
374
|
toolCalls[tc.index].arguments += tc.function.arguments;
|
|
366
|
-
// Feed
|
|
375
|
+
// Feed settle argument deltas to the parser for progressive
|
|
367
376
|
// streaming, but only when it appears to be the sole tool call.
|
|
368
|
-
if (answerStreamer.detected && toolCalls[tc.index].name === "
|
|
377
|
+
if (answerStreamer.detected && toolCalls[tc.index].name === "settle"
|
|
369
378
|
&& Object.keys(toolCalls).length === 1) {
|
|
370
379
|
answerStreamer.processDelta(tc.function.arguments);
|
|
371
380
|
}
|
|
@@ -381,10 +390,10 @@ async function streamChatCompletion(client, createParams, callbacks, signal) {
|
|
|
381
390
|
toolCalls: Object.values(toolCalls),
|
|
382
391
|
outputItems: [],
|
|
383
392
|
usage,
|
|
384
|
-
|
|
393
|
+
settleStreamed: answerStreamer.streamed,
|
|
385
394
|
};
|
|
386
395
|
}
|
|
387
|
-
async function streamResponsesApi(client, createParams, callbacks, signal) {
|
|
396
|
+
async function streamResponsesApi(client, createParams, callbacks, signal, eagerSettleStreaming = true) {
|
|
388
397
|
(0, runtime_1.emitNervesEvent)({
|
|
389
398
|
component: "engine",
|
|
390
399
|
event: "engine.stream_start",
|
|
@@ -399,7 +408,7 @@ async function streamResponsesApi(client, createParams, callbacks, signal) {
|
|
|
399
408
|
const outputItems = [];
|
|
400
409
|
let currentToolCall = null;
|
|
401
410
|
let usage;
|
|
402
|
-
const answerStreamer = new
|
|
411
|
+
const answerStreamer = new SettleStreamer(callbacks, eagerSettleStreaming);
|
|
403
412
|
let functionCallCount = 0;
|
|
404
413
|
for await (const event of response) {
|
|
405
414
|
if (signal?.aborted)
|
|
@@ -429,10 +438,10 @@ async function streamResponsesApi(client, createParams, callbacks, signal) {
|
|
|
429
438
|
name: String(event.item.name),
|
|
430
439
|
arguments: "",
|
|
431
440
|
};
|
|
432
|
-
// Detect
|
|
441
|
+
// Detect settle function call -- clear any streamed noise.
|
|
433
442
|
// Only activate when this is the first (and so far only) function call.
|
|
434
443
|
// Mixed calls are rejected by core.ts; no need to stream their args.
|
|
435
|
-
if (String(event.item.name) === "
|
|
444
|
+
if (String(event.item.name) === "settle" && functionCallCount === 1) {
|
|
436
445
|
answerStreamer.activate();
|
|
437
446
|
}
|
|
438
447
|
}
|
|
@@ -441,9 +450,9 @@ async function streamResponsesApi(client, createParams, callbacks, signal) {
|
|
|
441
450
|
case "response.function_call_arguments.delta": {
|
|
442
451
|
if (currentToolCall) {
|
|
443
452
|
currentToolCall.arguments += event.delta;
|
|
444
|
-
// Feed
|
|
453
|
+
// Feed settle argument deltas to the parser for progressive
|
|
445
454
|
// streaming, but only when it appears to be the sole function call.
|
|
446
|
-
if (answerStreamer.detected && currentToolCall.name === "
|
|
455
|
+
if (answerStreamer.detected && currentToolCall.name === "settle"
|
|
447
456
|
&& functionCallCount === 1) {
|
|
448
457
|
answerStreamer.processDelta(String(event.delta));
|
|
449
458
|
}
|
|
@@ -485,6 +494,6 @@ async function streamResponsesApi(client, createParams, callbacks, signal) {
|
|
|
485
494
|
toolCalls,
|
|
486
495
|
outputItems,
|
|
487
496
|
usage,
|
|
488
|
-
|
|
497
|
+
settleStreamed: answerStreamer.streamed,
|
|
489
498
|
};
|
|
490
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
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.listTargetSessionCandidates = listTargetSessionCandidates;
|
|
4
|
+
exports.formatTargetSessionCandidates = formatTargetSessionCandidates;
|
|
5
|
+
const session_transcript_1 = require("./session-transcript");
|
|
6
|
+
const session_activity_1 = require("./session-activity");
|
|
7
|
+
const trust_explanation_1 = require("../mind/friends/trust-explanation");
|
|
8
|
+
const runtime_1 = require("../nerves/runtime");
|
|
9
|
+
function synthesizeFriendRecord(candidate) {
|
|
10
|
+
return {
|
|
11
|
+
id: candidate.friendId,
|
|
12
|
+
name: candidate.friendName,
|
|
13
|
+
role: "stranger",
|
|
14
|
+
trustLevel: "stranger",
|
|
15
|
+
connections: [],
|
|
16
|
+
externalIds: [],
|
|
17
|
+
tenantMemberships: [],
|
|
18
|
+
toolPreferences: {},
|
|
19
|
+
notes: {},
|
|
20
|
+
totalTokens: 0,
|
|
21
|
+
createdAt: new Date(0).toISOString(),
|
|
22
|
+
updatedAt: new Date(0).toISOString(),
|
|
23
|
+
schemaVersion: 1,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function deliveryPriority(mode) {
|
|
27
|
+
if (mode === "deliver_now")
|
|
28
|
+
return 0;
|
|
29
|
+
if (mode === "queue_only")
|
|
30
|
+
return 1;
|
|
31
|
+
return 2;
|
|
32
|
+
}
|
|
33
|
+
function activityPriority(source) {
|
|
34
|
+
return source === "friend-facing" ? 0 : 1;
|
|
35
|
+
}
|
|
36
|
+
function describeDelivery(candidate) {
|
|
37
|
+
if (candidate.channel === "mcp") {
|
|
38
|
+
// MCP can't push (no proactive API), but can queue — dev tool picks up via check_response
|
|
39
|
+
return { mode: "queue_only", reason: "MCP session — message queued for dev tool to pick up via check_response" };
|
|
40
|
+
}
|
|
41
|
+
if (candidate.channel !== "bluebubbles" && candidate.channel !== "teams") {
|
|
42
|
+
return { mode: "blocked", reason: "this channel does not support proactive outward delivery yet" };
|
|
43
|
+
}
|
|
44
|
+
if (candidate.trust.level === "family" || candidate.trust.level === "friend") {
|
|
45
|
+
return { mode: "deliver_now", reason: "directly trusted target on a proactive-delivery channel" };
|
|
46
|
+
}
|
|
47
|
+
return { mode: "queue_only", reason: "visible as a live chat, but immediate delivery still needs explicit cross-chat authorization" };
|
|
48
|
+
}
|
|
49
|
+
async function listTargetSessionCandidates(input) {
|
|
50
|
+
(0, runtime_1.emitNervesEvent)({
|
|
51
|
+
component: "engine",
|
|
52
|
+
event: "engine.target_resolution_start",
|
|
53
|
+
message: "listing live target session candidates",
|
|
54
|
+
meta: {
|
|
55
|
+
sessionsDir: input.sessionsDir,
|
|
56
|
+
currentSession: input.currentSession
|
|
57
|
+
? `${input.currentSession.friendId}/${input.currentSession.channel}/${input.currentSession.key}`
|
|
58
|
+
: null,
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
const activity = (0, session_activity_1.listSessionActivity)({
|
|
62
|
+
sessionsDir: input.sessionsDir,
|
|
63
|
+
friendsDir: input.friendsDir,
|
|
64
|
+
agentName: input.agentName,
|
|
65
|
+
currentSession: input.currentSession ?? null,
|
|
66
|
+
}).filter((entry) => entry.channel !== "inner");
|
|
67
|
+
const candidates = [];
|
|
68
|
+
for (const entry of activity) {
|
|
69
|
+
const friend = await input.friendStore.get(entry.friendId) ?? synthesizeFriendRecord(entry);
|
|
70
|
+
const trust = (0, trust_explanation_1.describeTrustContext)({
|
|
71
|
+
friend,
|
|
72
|
+
channel: entry.channel,
|
|
73
|
+
});
|
|
74
|
+
const sessionTail = await (0, session_transcript_1.summarizeSessionTail)({
|
|
75
|
+
sessionPath: entry.sessionPath,
|
|
76
|
+
friendId: entry.friendId,
|
|
77
|
+
channel: entry.channel,
|
|
78
|
+
key: entry.key,
|
|
79
|
+
messageCount: 6,
|
|
80
|
+
summarize: input.summarize,
|
|
81
|
+
trustLevel: trust.level,
|
|
82
|
+
});
|
|
83
|
+
const snapshot = sessionTail.kind === "ok"
|
|
84
|
+
? sessionTail.snapshot
|
|
85
|
+
: sessionTail.kind === "empty"
|
|
86
|
+
? "recent focus: no recent visible messages"
|
|
87
|
+
: "recent focus: session transcript unavailable";
|
|
88
|
+
const delivery = describeDelivery({
|
|
89
|
+
channel: entry.channel,
|
|
90
|
+
trust,
|
|
91
|
+
});
|
|
92
|
+
candidates.push({
|
|
93
|
+
friendId: entry.friendId,
|
|
94
|
+
friendName: entry.friendName,
|
|
95
|
+
channel: entry.channel,
|
|
96
|
+
key: entry.key,
|
|
97
|
+
sessionPath: entry.sessionPath,
|
|
98
|
+
snapshot,
|
|
99
|
+
trust,
|
|
100
|
+
delivery,
|
|
101
|
+
lastActivityAt: entry.lastActivityAt,
|
|
102
|
+
lastActivityMs: entry.lastActivityMs,
|
|
103
|
+
activitySource: entry.activitySource,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
return candidates.sort((a, b) => {
|
|
107
|
+
const deliveryDiff = deliveryPriority(a.delivery.mode) - deliveryPriority(b.delivery.mode);
|
|
108
|
+
if (deliveryDiff !== 0)
|
|
109
|
+
return deliveryDiff;
|
|
110
|
+
const sourceDiff = activityPriority(a.activitySource) - activityPriority(b.activitySource);
|
|
111
|
+
if (sourceDiff !== 0)
|
|
112
|
+
return sourceDiff;
|
|
113
|
+
return b.lastActivityMs - a.lastActivityMs;
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
function formatTargetSessionCandidates(candidates) {
|
|
117
|
+
if (candidates.length === 0)
|
|
118
|
+
return "";
|
|
119
|
+
const lines = ["## candidate target chats"];
|
|
120
|
+
for (const candidate of candidates) {
|
|
121
|
+
lines.push(`- ${candidate.friendName} [${candidate.friendId}] via ${candidate.channel}/${candidate.key}`);
|
|
122
|
+
lines.push(` trust: ${candidate.trust.level} (${candidate.trust.basis}) — ${candidate.trust.summary}`);
|
|
123
|
+
lines.push(` delivery: ${candidate.delivery.mode} — ${candidate.delivery.reason}`);
|
|
124
|
+
lines.push(` snapshot: ${candidate.snapshot}`);
|
|
125
|
+
}
|
|
126
|
+
return lines.join("\n");
|
|
127
|
+
}
|