@ouro.bot/cli 0.1.0-alpha.49 → 0.1.0-alpha.490
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 +133 -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 +3118 -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 +989 -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 +281 -0
- package/dist/heart/bridges/manager.js +37 -0
- package/dist/heart/bridges/state-machine.js +20 -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 +119 -129
- package/dist/heart/core.js +758 -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 +7229 -0
- package/dist/heart/daemon/cli-help.js +493 -0
- package/dist/heart/daemon/cli-parse.js +1533 -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 +162 -17
- 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/mail-import-discovery.js +353 -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 +103 -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 +382 -0
- package/dist/heart/outlook/readers/continuity-readers.js +336 -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 +301 -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 +104 -13
- 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 +63 -39
- 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 +981 -0
- package/dist/heart/session-transcript.js +167 -0
- package/dist/heart/start-of-turn-packet.js +345 -0
- package/dist/heart/streaming.js +48 -28
- 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 +372 -0
- 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 +600 -0
- package/dist/mailroom/core.js +658 -0
- package/dist/mailroom/entry.js +160 -0
- package/dist/mailroom/file-store.js +426 -0
- package/dist/mailroom/mbox-import.js +382 -0
- package/dist/mailroom/outbound.js +380 -0
- package/dist/mailroom/policy.js +263 -0
- package/dist/mailroom/reader.js +219 -0
- package/dist/mailroom/search-cache.js +182 -0
- package/dist/mailroom/search-relevance.js +319 -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 +164 -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 +54 -2
- 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 +56 -8
- package/dist/mind/prompt-refresh.js +3 -2
- package/dist/mind/prompt.js +973 -168
- 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 +93 -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-Cm51CY9W.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 +31 -5
- package/dist/repertoire/tasks/fix.js +182 -0
- package/dist/repertoire/tasks/index.js +16 -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 +46 -842
- 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 +1281 -0
- package/dist/repertoire/tools-notes.js +376 -0
- package/dist/repertoire/tools-session.js +749 -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-trip.js +280 -0
- package/dist/repertoire/tools-user-profile.js +144 -0
- package/dist/repertoire/tools-vault.js +40 -0
- package/dist/repertoire/tools.js +144 -115
- 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} +20 -3
- package/dist/senses/bluebubbles/index.js +1835 -0
- 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/processed-log.js +111 -0
- 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 +515 -211
- package/dist/senses/commands.js +66 -3
- package/dist/senses/habit-turn-message.js +108 -0
- package/dist/senses/inner-dialog-worker.js +110 -20
- package/dist/senses/inner-dialog.js +408 -21
- package/dist/senses/mail-entry.js +66 -0
- package/dist/senses/mail.js +379 -0
- package/dist/senses/pipeline.js +588 -81
- 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 +412 -163
- package/dist/senses/trust-gate.js +100 -5
- package/dist/trips/core.js +138 -0
- package/dist/trips/store.js +146 -0
- 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/heart/session-recall.js +0 -116
- package/dist/mind/associative-recall.js +0 -209
- package/dist/senses/bluebubbles-entry.js +0 -13
- package/dist/senses/bluebubbles.js +0 -1032
- 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
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.upsertGroupContextParticipants = upsertGroupContextParticipants;
|
|
4
|
+
const node_crypto_1 = require("node:crypto");
|
|
5
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
6
|
+
const CURRENT_SCHEMA_VERSION = 1;
|
|
7
|
+
function normalizeDisplayName(externalId, displayName) {
|
|
8
|
+
const trimmed = displayName?.trim();
|
|
9
|
+
return trimmed && trimmed.length > 0 ? trimmed : externalId;
|
|
10
|
+
}
|
|
11
|
+
function buildNameNotes(name, now) {
|
|
12
|
+
return name !== "Unknown"
|
|
13
|
+
? { name: { value: name, savedAt: now } }
|
|
14
|
+
: {};
|
|
15
|
+
}
|
|
16
|
+
function dedupeParticipants(participants) {
|
|
17
|
+
const deduped = new Map();
|
|
18
|
+
for (const participant of participants) {
|
|
19
|
+
const externalId = participant.externalId.trim();
|
|
20
|
+
if (!externalId)
|
|
21
|
+
continue;
|
|
22
|
+
const key = `${participant.provider}:${externalId}`;
|
|
23
|
+
if (!deduped.has(key)) {
|
|
24
|
+
deduped.set(key, {
|
|
25
|
+
...participant,
|
|
26
|
+
externalId,
|
|
27
|
+
displayName: participant.displayName?.trim() || undefined,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return Array.from(deduped.values());
|
|
32
|
+
}
|
|
33
|
+
function createGroupExternalId(provider, groupExternalId, linkedAt) {
|
|
34
|
+
return {
|
|
35
|
+
provider,
|
|
36
|
+
externalId: groupExternalId,
|
|
37
|
+
linkedAt,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function shouldPromoteToAcquaintance(friend) {
|
|
41
|
+
return (friend.trustLevel ?? "stranger") === "stranger";
|
|
42
|
+
}
|
|
43
|
+
function createAcquaintanceRecord(participant, groupExternalId, linkedAt) {
|
|
44
|
+
const name = normalizeDisplayName(participant.externalId, participant.displayName);
|
|
45
|
+
return {
|
|
46
|
+
id: (0, node_crypto_1.randomUUID)(),
|
|
47
|
+
name,
|
|
48
|
+
role: "acquaintance",
|
|
49
|
+
trustLevel: "acquaintance",
|
|
50
|
+
connections: [],
|
|
51
|
+
externalIds: [
|
|
52
|
+
{
|
|
53
|
+
provider: participant.provider,
|
|
54
|
+
externalId: participant.externalId,
|
|
55
|
+
linkedAt,
|
|
56
|
+
},
|
|
57
|
+
createGroupExternalId(participant.provider, groupExternalId, linkedAt),
|
|
58
|
+
],
|
|
59
|
+
tenantMemberships: [],
|
|
60
|
+
toolPreferences: {},
|
|
61
|
+
notes: buildNameNotes(name, linkedAt),
|
|
62
|
+
totalTokens: 0,
|
|
63
|
+
createdAt: linkedAt,
|
|
64
|
+
updatedAt: linkedAt,
|
|
65
|
+
schemaVersion: CURRENT_SCHEMA_VERSION,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
async function upsertGroupContextParticipants(input) {
|
|
69
|
+
(0, runtime_1.emitNervesEvent)({
|
|
70
|
+
component: "friends",
|
|
71
|
+
event: "friends.group_context_upsert_start",
|
|
72
|
+
message: "upserting shared-group participant context",
|
|
73
|
+
meta: {
|
|
74
|
+
participantCount: input.participants.length,
|
|
75
|
+
hasGroupExternalId: input.groupExternalId.trim().length > 0,
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
const groupExternalId = input.groupExternalId.trim();
|
|
79
|
+
if (!groupExternalId) {
|
|
80
|
+
return [];
|
|
81
|
+
}
|
|
82
|
+
const now = input.now ?? (() => new Date().toISOString());
|
|
83
|
+
const participants = dedupeParticipants(input.participants);
|
|
84
|
+
const results = [];
|
|
85
|
+
for (const participant of participants) {
|
|
86
|
+
const linkedAt = now();
|
|
87
|
+
const existing = await input.store.findByExternalId(participant.provider, participant.externalId);
|
|
88
|
+
if (!existing) {
|
|
89
|
+
const created = createAcquaintanceRecord(participant, groupExternalId, linkedAt);
|
|
90
|
+
await input.store.put(created.id, created);
|
|
91
|
+
results.push({
|
|
92
|
+
friendId: created.id,
|
|
93
|
+
name: created.name,
|
|
94
|
+
trustLevel: "acquaintance",
|
|
95
|
+
created: true,
|
|
96
|
+
updated: false,
|
|
97
|
+
addedGroupExternalId: true,
|
|
98
|
+
});
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
const hasGroupExternalId = existing.externalIds.some((externalId) => externalId.externalId === groupExternalId);
|
|
102
|
+
const promoteToAcquaintance = shouldPromoteToAcquaintance(existing);
|
|
103
|
+
const trustLevel = promoteToAcquaintance
|
|
104
|
+
? "acquaintance"
|
|
105
|
+
: existing.trustLevel;
|
|
106
|
+
const role = promoteToAcquaintance
|
|
107
|
+
? "acquaintance"
|
|
108
|
+
: existing.role;
|
|
109
|
+
const updatedExternalIds = hasGroupExternalId
|
|
110
|
+
? existing.externalIds
|
|
111
|
+
: [...existing.externalIds, createGroupExternalId(participant.provider, groupExternalId, linkedAt)];
|
|
112
|
+
const updated = promoteToAcquaintance || !hasGroupExternalId;
|
|
113
|
+
const record = updated
|
|
114
|
+
? {
|
|
115
|
+
...existing,
|
|
116
|
+
role,
|
|
117
|
+
trustLevel,
|
|
118
|
+
externalIds: updatedExternalIds,
|
|
119
|
+
updatedAt: linkedAt,
|
|
120
|
+
}
|
|
121
|
+
: existing;
|
|
122
|
+
if (updated) {
|
|
123
|
+
await input.store.put(record.id, record);
|
|
124
|
+
}
|
|
125
|
+
results.push({
|
|
126
|
+
friendId: record.id,
|
|
127
|
+
name: record.name,
|
|
128
|
+
trustLevel,
|
|
129
|
+
created: false,
|
|
130
|
+
updated,
|
|
131
|
+
addedGroupExternalId: !hasGroupExternalId,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
(0, runtime_1.emitNervesEvent)({
|
|
135
|
+
component: "friends",
|
|
136
|
+
event: "friends.group_context_upsert_end",
|
|
137
|
+
message: "upserted shared-group participant context",
|
|
138
|
+
meta: {
|
|
139
|
+
participantCount: participants.length,
|
|
140
|
+
updatedCount: results.filter((result) => result.created || result.updated).length,
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
return results;
|
|
144
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
// FriendResolver -- resolves external identity into a FriendRecord + channel capabilities.
|
|
3
3
|
// Created per-request (per-incoming-message), per-friend.
|
|
4
|
-
// Replaces the old ContextResolver: no authority checker, no separate
|
|
4
|
+
// Replaces the old ContextResolver: no authority checker, no separate note resolution.
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.FriendResolver = void 0;
|
|
7
7
|
const crypto_1 = require("crypto");
|
|
@@ -31,6 +31,43 @@ class FriendResolver {
|
|
|
31
31
|
}
|
|
32
32
|
if (existing)
|
|
33
33
|
return existing;
|
|
34
|
+
// Migration: local provider previously used "${username}@${hostname}" format.
|
|
35
|
+
// If no exact match, try finding a friend with old-format external ID.
|
|
36
|
+
/* v8 ignore start -- migration path: only fires when legacy hostname-format friend exists @preserve */
|
|
37
|
+
if (this.params.provider === "local" && !this.params.externalId.includes("@")) {
|
|
38
|
+
try {
|
|
39
|
+
const all = typeof this.store.listAll === "function" ? await this.store.listAll() : [];
|
|
40
|
+
/* v8 ignore start -- migration path: only fires when legacy hostname-format friend exists @preserve */
|
|
41
|
+
const migrationMatch = all.find((f) => f.externalIds.some((eid) => eid.provider === "local" && eid.externalId.startsWith(this.params.externalId + "@")));
|
|
42
|
+
if (migrationMatch) {
|
|
43
|
+
const now = new Date().toISOString();
|
|
44
|
+
migrationMatch.externalIds.push({
|
|
45
|
+
provider: this.params.provider,
|
|
46
|
+
externalId: this.params.externalId,
|
|
47
|
+
linkedAt: now,
|
|
48
|
+
});
|
|
49
|
+
migrationMatch.updatedAt = now;
|
|
50
|
+
try {
|
|
51
|
+
await this.store.put(migrationMatch.id, migrationMatch);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
// best-effort persist
|
|
55
|
+
}
|
|
56
|
+
(0, runtime_1.emitNervesEvent)({
|
|
57
|
+
component: "friends",
|
|
58
|
+
event: "friends.local_id_migrated",
|
|
59
|
+
message: `migrated local friend identity from hostname format to username-only`,
|
|
60
|
+
meta: { friendId: migrationMatch.id, newExternalId: this.params.externalId },
|
|
61
|
+
});
|
|
62
|
+
return migrationMatch;
|
|
63
|
+
}
|
|
64
|
+
/* v8 ignore stop */
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
// fall through to create new
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/* v8 ignore stop */
|
|
34
71
|
// First encounter -- create new FriendRecord
|
|
35
72
|
const now = new Date().toISOString();
|
|
36
73
|
const externalId = {
|
|
@@ -50,6 +87,21 @@ class FriendResolver {
|
|
|
50
87
|
hasAnyFriends = false;
|
|
51
88
|
}
|
|
52
89
|
const isFirstImprint = !hasAnyFriends;
|
|
90
|
+
// BlueBubbles group chats route through here as `imessage-handle` with an
|
|
91
|
+
// externalId of the form `group:any;+;<chatHash>`. When the harness auto-
|
|
92
|
+
// creates the group friend at stranger trust, we mark the record so that
|
|
93
|
+
// the trust gate can surface the relationship for explicit acknowledgment
|
|
94
|
+
// later instead of letting messages accumulate silently.
|
|
95
|
+
const isImessageGroup = this.params.provider === "imessage-handle" &&
|
|
96
|
+
typeof this.params.externalId === "string" &&
|
|
97
|
+
this.params.externalId.startsWith("group:");
|
|
98
|
+
const notes = {};
|
|
99
|
+
if (this.params.displayName !== "Unknown") {
|
|
100
|
+
notes.name = { value: this.params.displayName, savedAt: now };
|
|
101
|
+
}
|
|
102
|
+
if (isImessageGroup && !isFirstImprint) {
|
|
103
|
+
notes.autoCreatedGroup = { value: "true", savedAt: now };
|
|
104
|
+
}
|
|
53
105
|
const friend = {
|
|
54
106
|
id: (0, crypto_1.randomUUID)(),
|
|
55
107
|
name: this.params.displayName,
|
|
@@ -59,7 +111,7 @@ class FriendResolver {
|
|
|
59
111
|
externalIds: [externalId],
|
|
60
112
|
tenantMemberships,
|
|
61
113
|
toolPreferences: {},
|
|
62
|
-
notes
|
|
114
|
+
notes,
|
|
63
115
|
totalTokens: 0,
|
|
64
116
|
createdAt: now,
|
|
65
117
|
updatedAt: now,
|
|
@@ -55,10 +55,29 @@ class FileFriendStore {
|
|
|
55
55
|
});
|
|
56
56
|
}
|
|
57
57
|
async get(id) {
|
|
58
|
+
// Direct UUID lookup
|
|
58
59
|
const record = await this.readJson(path.join(this.friendsPath, `${id}.json`));
|
|
59
|
-
if (
|
|
60
|
-
return
|
|
61
|
-
|
|
60
|
+
if (record)
|
|
61
|
+
return this.normalize(record);
|
|
62
|
+
// Fallback: if id is a name (not UUID), scan for matching friend
|
|
63
|
+
/* v8 ignore start -- name fallback: exercised by live proactive sends @preserve */
|
|
64
|
+
try {
|
|
65
|
+
const entries = await fsPromises.readdir(this.friendsPath);
|
|
66
|
+
for (const entry of entries) {
|
|
67
|
+
if (!entry.endsWith(".json"))
|
|
68
|
+
continue;
|
|
69
|
+
const raw = await this.readJson(path.join(this.friendsPath, entry));
|
|
70
|
+
if (!raw)
|
|
71
|
+
continue;
|
|
72
|
+
const normalized = this.normalize(raw);
|
|
73
|
+
if (normalized.name?.toLowerCase() === id.toLowerCase()) {
|
|
74
|
+
return normalized;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
catch { /* directory unreadable — return null */ }
|
|
79
|
+
/* v8 ignore stop */
|
|
80
|
+
return null;
|
|
62
81
|
}
|
|
63
82
|
async put(id, record) {
|
|
64
83
|
await this.writeJson(path.join(this.friendsPath, `${id}.json`), this.normalize(record));
|
|
@@ -127,6 +146,8 @@ class FileFriendStore {
|
|
|
127
146
|
trustLevel === "stranger"
|
|
128
147
|
? trustLevel
|
|
129
148
|
: DEFAULT_TRUST_LEVEL;
|
|
149
|
+
const kind = raw.kind === "human" || raw.kind === "agent" ? raw.kind : "human";
|
|
150
|
+
const agentMeta = kind === "agent" ? this.normalizeAgentMeta(raw.agentMeta) : undefined;
|
|
130
151
|
return {
|
|
131
152
|
id: raw.id,
|
|
132
153
|
name: raw.name,
|
|
@@ -153,6 +174,21 @@ class FileFriendStore {
|
|
|
153
174
|
createdAt: typeof raw.createdAt === "string" ? raw.createdAt : new Date().toISOString(),
|
|
154
175
|
updatedAt: typeof raw.updatedAt === "string" ? raw.updatedAt : new Date().toISOString(),
|
|
155
176
|
schemaVersion: typeof raw.schemaVersion === "number" ? raw.schemaVersion : 1,
|
|
177
|
+
kind,
|
|
178
|
+
agentMeta,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
normalizeAgentMeta(raw) {
|
|
182
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
183
|
+
return undefined;
|
|
184
|
+
const meta = raw;
|
|
185
|
+
if (typeof meta.bundleName !== "string")
|
|
186
|
+
return undefined;
|
|
187
|
+
return {
|
|
188
|
+
bundleName: meta.bundleName,
|
|
189
|
+
familiarity: typeof meta.familiarity === "number" ? meta.familiarity : 0,
|
|
190
|
+
sharedMissions: Array.isArray(meta.sharedMissions) ? meta.sharedMissions : [],
|
|
191
|
+
outcomes: Array.isArray(meta.outcomes) ? meta.outcomes : [],
|
|
156
192
|
};
|
|
157
193
|
}
|
|
158
194
|
async readJson(filePath) {
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.describeTrustContext = describeTrustContext;
|
|
4
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
5
|
+
function findRelatedGroupId(friend) {
|
|
6
|
+
return friend.externalIds.find((externalId) => externalId.externalId.startsWith("group:"))?.externalId;
|
|
7
|
+
}
|
|
8
|
+
function resolveLevel(friend) {
|
|
9
|
+
return friend.trustLevel ?? "stranger";
|
|
10
|
+
}
|
|
11
|
+
function describeTrustContext(input) {
|
|
12
|
+
const level = resolveLevel(input.friend);
|
|
13
|
+
const relatedGroupId = findRelatedGroupId(input.friend);
|
|
14
|
+
const explanation = level === "family" || level === "friend"
|
|
15
|
+
? {
|
|
16
|
+
level,
|
|
17
|
+
basis: "direct",
|
|
18
|
+
summary: level === "family"
|
|
19
|
+
? "direct family trust"
|
|
20
|
+
: "direct trusted relationship",
|
|
21
|
+
why: "this relationship is directly trusted rather than inferred through a shared group or cold first contact.",
|
|
22
|
+
permits: [
|
|
23
|
+
"local operations when appropriate",
|
|
24
|
+
"proactive follow-through",
|
|
25
|
+
"full collaborative problem solving",
|
|
26
|
+
],
|
|
27
|
+
constraints: [],
|
|
28
|
+
}
|
|
29
|
+
: level === "acquaintance"
|
|
30
|
+
? {
|
|
31
|
+
level,
|
|
32
|
+
basis: "shared_group",
|
|
33
|
+
summary: relatedGroupId
|
|
34
|
+
? "known through the shared project group"
|
|
35
|
+
: "known through a shared group context",
|
|
36
|
+
why: relatedGroupId
|
|
37
|
+
? `this trust comes from the shared group context ${relatedGroupId}, not from direct endorsement.`
|
|
38
|
+
: "this trust comes from shared group context rather than direct endorsement.",
|
|
39
|
+
permits: [
|
|
40
|
+
"group-safe coordination",
|
|
41
|
+
"normal conversation inside the shared context",
|
|
42
|
+
],
|
|
43
|
+
constraints: [
|
|
44
|
+
"guarded local actions",
|
|
45
|
+
"do not assume broad private authority",
|
|
46
|
+
],
|
|
47
|
+
relatedGroupId,
|
|
48
|
+
}
|
|
49
|
+
: {
|
|
50
|
+
level,
|
|
51
|
+
basis: "unknown",
|
|
52
|
+
summary: "truly unknown first-contact context",
|
|
53
|
+
why: "this person is not known through direct trust or a shared group context.",
|
|
54
|
+
permits: [
|
|
55
|
+
"safe first-contact orientation only",
|
|
56
|
+
],
|
|
57
|
+
constraints: [
|
|
58
|
+
"first contact does not reach the full model on open channels",
|
|
59
|
+
"no local or privileged actions",
|
|
60
|
+
],
|
|
61
|
+
};
|
|
62
|
+
(0, runtime_1.emitNervesEvent)({
|
|
63
|
+
component: "friends",
|
|
64
|
+
event: "friends.trust_explained",
|
|
65
|
+
message: "built explicit trust explanation",
|
|
66
|
+
meta: {
|
|
67
|
+
channel: input.channel,
|
|
68
|
+
level: explanation.level,
|
|
69
|
+
basis: explanation.basis,
|
|
70
|
+
hasRelatedGroup: Boolean(explanation.relatedGroupId),
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
return explanation;
|
|
74
|
+
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
// Context kernel type definitions.
|
|
3
|
-
// FriendRecord (merged identity +
|
|
3
|
+
// FriendRecord (merged identity + notes), channel capabilities, and resolved context.
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
5
|
exports.TRUSTED_LEVELS = void 0;
|
|
6
6
|
exports.isIdentityProvider = isIdentityProvider;
|
|
7
7
|
exports.isIntegration = isIntegration;
|
|
8
8
|
exports.isTrustedLevel = isTrustedLevel;
|
|
9
9
|
const runtime_1 = require("../../nerves/runtime");
|
|
10
|
-
const IDENTITY_PROVIDERS = new Set(["aad", "local", "teams-conversation", "imessage-handle"]);
|
|
10
|
+
const IDENTITY_PROVIDERS = new Set(["aad", "local", "teams-conversation", "imessage-handle", "email-address"]);
|
|
11
11
|
function isIdentityProvider(value) {
|
|
12
12
|
(0, runtime_1.emitNervesEvent)({
|
|
13
13
|
component: "friends",
|
|
@@ -0,0 +1,161 @@
|
|
|
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.indexJournalFiles = indexJournalFiles;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const runtime_1 = require("../nerves/runtime");
|
|
40
|
+
const TEXT_EXTENSIONS = new Set([".md", ".txt"]);
|
|
41
|
+
const PREVIEW_CHAR_LIMIT = 500;
|
|
42
|
+
function readExistingIndex(indexPath) {
|
|
43
|
+
try {
|
|
44
|
+
const raw = fs.readFileSync(indexPath, "utf8");
|
|
45
|
+
const parsed = JSON.parse(raw);
|
|
46
|
+
if (!Array.isArray(parsed))
|
|
47
|
+
return [];
|
|
48
|
+
return parsed;
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return [];
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function extractPreview(content) {
|
|
55
|
+
const trimmed = content.trim();
|
|
56
|
+
if (!trimmed)
|
|
57
|
+
return "";
|
|
58
|
+
return trimmed.split("\n")[0].replace(/^#+\s*/, "").trim();
|
|
59
|
+
}
|
|
60
|
+
async function indexJournalFiles(journalDir, indexPath, embedProvider) {
|
|
61
|
+
// Read existing index
|
|
62
|
+
const existingIndex = readExistingIndex(indexPath);
|
|
63
|
+
const indexMap = new Map();
|
|
64
|
+
for (const entry of existingIndex) {
|
|
65
|
+
indexMap.set(entry.filename, entry);
|
|
66
|
+
}
|
|
67
|
+
// Scan journal dir for text files
|
|
68
|
+
let dirEntries;
|
|
69
|
+
try {
|
|
70
|
+
dirEntries = fs.readdirSync(journalDir, { withFileTypes: true });
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
(0, runtime_1.emitNervesEvent)({
|
|
74
|
+
component: "mind",
|
|
75
|
+
event: "mind.journal_index_scan",
|
|
76
|
+
message: "journal dir not found or unreadable",
|
|
77
|
+
meta: { journalDir },
|
|
78
|
+
});
|
|
79
|
+
return 0;
|
|
80
|
+
}
|
|
81
|
+
const textFiles = dirEntries.filter((entry) => {
|
|
82
|
+
if (!entry.isFile())
|
|
83
|
+
return false;
|
|
84
|
+
if (entry.name.startsWith("."))
|
|
85
|
+
return false;
|
|
86
|
+
const ext = path.extname(entry.name).toLowerCase();
|
|
87
|
+
return TEXT_EXTENSIONS.has(ext);
|
|
88
|
+
});
|
|
89
|
+
if (textFiles.length === 0) {
|
|
90
|
+
(0, runtime_1.emitNervesEvent)({
|
|
91
|
+
component: "mind",
|
|
92
|
+
event: "mind.journal_index_scan",
|
|
93
|
+
message: "no text files found in journal",
|
|
94
|
+
meta: { journalDir },
|
|
95
|
+
});
|
|
96
|
+
return 0;
|
|
97
|
+
}
|
|
98
|
+
let newlyIndexed = 0;
|
|
99
|
+
for (const file of textFiles) {
|
|
100
|
+
const filePath = path.join(journalDir, file.name);
|
|
101
|
+
let stat;
|
|
102
|
+
try {
|
|
103
|
+
stat = fs.statSync(filePath);
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
/* v8 ignore next -- filesystem race: file deleted between readdir and stat @preserve */
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
// Check if already indexed with same mtime
|
|
110
|
+
const existing = indexMap.get(file.name);
|
|
111
|
+
if (existing && existing.mtime === stat.mtimeMs) {
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
// Read content for embedding
|
|
115
|
+
let content;
|
|
116
|
+
try {
|
|
117
|
+
content = fs.readFileSync(filePath, "utf8");
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
/* v8 ignore next -- filesystem race: file deleted between stat and read @preserve */
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
const preview = extractPreview(content);
|
|
124
|
+
const embedText = content.slice(0, PREVIEW_CHAR_LIMIT);
|
|
125
|
+
// Generate embedding
|
|
126
|
+
let embedding;
|
|
127
|
+
try {
|
|
128
|
+
const vectors = await embedProvider.embed([embedText]);
|
|
129
|
+
embedding = vectors[0] ?? [];
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
(0, runtime_1.emitNervesEvent)({
|
|
133
|
+
level: "warn",
|
|
134
|
+
component: "mind",
|
|
135
|
+
event: "mind.journal_embedding_error",
|
|
136
|
+
message: "embedding failed for journal file",
|
|
137
|
+
meta: { filename: file.name },
|
|
138
|
+
});
|
|
139
|
+
embedding = [];
|
|
140
|
+
}
|
|
141
|
+
indexMap.set(file.name, {
|
|
142
|
+
filename: file.name,
|
|
143
|
+
embedding,
|
|
144
|
+
mtime: stat.mtimeMs,
|
|
145
|
+
preview,
|
|
146
|
+
});
|
|
147
|
+
newlyIndexed++;
|
|
148
|
+
}
|
|
149
|
+
// Write updated index back
|
|
150
|
+
if (newlyIndexed > 0) {
|
|
151
|
+
const updatedIndex = Array.from(indexMap.values());
|
|
152
|
+
fs.writeFileSync(indexPath, JSON.stringify(updatedIndex, null, 2), "utf8");
|
|
153
|
+
}
|
|
154
|
+
(0, runtime_1.emitNervesEvent)({
|
|
155
|
+
component: "mind",
|
|
156
|
+
event: "mind.journal_index_complete",
|
|
157
|
+
message: "journal indexing complete",
|
|
158
|
+
meta: { journalDir, newlyIndexed, total: indexMap.size },
|
|
159
|
+
});
|
|
160
|
+
return newlyIndexed;
|
|
161
|
+
}
|