@amoree-code/ocean 0.0.0-stage → 1.2.0
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/LICENSE +21 -0
- package/README.md +284 -2
- package/dist/application/auth/auth-orchestrator.js +77 -0
- package/dist/application/clients/clients.js +646 -0
- package/dist/application/clients/editors.js +398 -0
- package/dist/application/clients/hooks.js +335 -0
- package/dist/application/clients/native.js +410 -0
- package/dist/application/clients/opencode-plugin.js +158 -0
- package/dist/application/clients/registry.js +188 -0
- package/dist/application/gateway/webhook-gateway.js +137 -0
- package/dist/application/install/provider-installer.js +184 -0
- package/dist/application/integrations/charter-copies.js +76 -0
- package/dist/application/integrations/claude-vscode.js +106 -0
- package/dist/application/integrations/engine-entry-repair.js +105 -0
- package/dist/application/integrations/skill-filter.js +254 -0
- package/dist/application/layout/layout-apply.js +443 -0
- package/dist/application/layout/layout-plan.js +236 -0
- package/dist/application/layout/workspace-template.js +34 -0
- package/dist/application/onboarding/state.js +23 -0
- package/dist/application/onboarding/steps.js +249 -0
- package/dist/application/profiles/profile-distribution.js +53 -0
- package/dist/application/profiles/profile-suggestion.js +39 -0
- package/dist/application/profiles/profile-upgrade-service.js +208 -0
- package/dist/application/pull/history-index.js +476 -0
- package/dist/application/pull/project-match.js +132 -0
- package/dist/application/pull/pull.js +202 -0
- package/dist/application/pull/server-capture.js +307 -0
- package/dist/application/scheduler/local-scheduler.js +210 -0
- package/dist/composition/runtime.js +64 -0
- package/dist/engine-root.js +9 -0
- package/dist/infrastructure/filesystem/profile-loader.js +46 -0
- package/dist/infrastructure/filesystem/runtime-config-loader.js +29 -0
- package/dist/infrastructure/filesystem/skill-loader.js +84 -0
- package/dist/infrastructure/filesystem/workspace-capability.js +37 -0
- package/dist/infrastructure/observability/runtime-logger.js +16 -0
- package/dist/infrastructure/process/agent-tool-executor.js +99 -0
- package/dist/infrastructure/process/cli-process.js +49 -0
- package/dist/infrastructure/process/interactive-process.js +145 -0
- package/dist/infrastructure/process/process-supervisor.js +194 -0
- package/dist/infrastructure/process/service.js +252 -0
- package/dist/infrastructure/providers/browser-provider.js +2 -0
- package/dist/infrastructure/providers/claude-sdk.js +137 -0
- package/dist/infrastructure/providers/client-home.js +14 -0
- package/dist/infrastructure/providers/fake-browser-provider.js +146 -0
- package/dist/infrastructure/providers/ollama-embedder.js +74 -0
- package/dist/infrastructure/providers/openai-compatible.js +268 -0
- package/dist/infrastructure/providers/playwright-browser-provider.js +380 -0
- package/dist/infrastructure/providers/provider-capabilities.js +50 -0
- package/dist/infrastructure/providers/provider-invocation.js +184 -0
- package/dist/infrastructure/providers/provider-registry.js +77 -0
- package/dist/infrastructure/providers/providers.js +134 -0
- package/dist/infrastructure/wrappers/wrapper-manager.js +374 -0
- package/dist/interfaces/cli/auth-command.js +54 -0
- package/dist/interfaces/cli/browser-bridge-command.js +93 -0
- package/dist/interfaces/cli/browser-command.js +119 -0
- package/dist/interfaces/cli/capture-command.js +125 -0
- package/dist/interfaces/cli/client-test-command.js +133 -0
- package/dist/interfaces/cli/clients-command.js +129 -0
- package/dist/interfaces/cli/command-registry.js +1211 -0
- package/dist/interfaces/cli/context-command.js +172 -0
- package/dist/interfaces/cli/daily-command.js +131 -0
- package/dist/interfaces/cli/governance-command.js +55 -0
- package/dist/interfaces/cli/handoff-command.js +35 -0
- package/dist/interfaces/cli/help-command.js +207 -0
- package/dist/interfaces/cli/idea-command.js +47 -0
- package/dist/interfaces/cli/intercept-command.js +317 -0
- package/dist/interfaces/cli/layout-command.js +27 -0
- package/dist/interfaces/cli/market-command.js +52 -0
- package/dist/interfaces/cli/mcp-gateway-command.js +30 -0
- package/dist/interfaces/cli/memory-command.js +317 -0
- package/dist/interfaces/cli/migrate-command.js +26 -0
- package/dist/interfaces/cli/observe-command.js +78 -0
- package/dist/interfaces/cli/onboard-command.js +123 -0
- package/dist/interfaces/cli/operate-command.js +59 -0
- package/dist/interfaces/cli/profiles-command.js +70 -0
- package/dist/interfaces/cli/pull-command.js +54 -0
- package/dist/interfaces/cli/setup-command.js +143 -0
- package/dist/interfaces/cli/tasks-command.js +249 -0
- package/dist/main.js +49 -0
- package/dist/node-warnings.js +17 -0
- package/dist/version.js +8 -0
- package/market/mcp/chrome-devtools/ocean.capability.json +28 -0
- package/market/mcp/gateway/ocean.capability.json +21 -0
- package/market/mcp/obsidian/ocean.capability.json +21 -0
- package/market/mcp/ocean/ocean.capability.json +21 -0
- package/market/mcp/playwright/ocean.capability.json +23 -0
- package/node_modules/@ocean/brain/dist/brain/brain-eval.js +29 -0
- package/node_modules/@ocean/brain/dist/brain/brain-markdown.js +226 -0
- package/node_modules/@ocean/brain/dist/brain/brain-reindex.js +247 -0
- package/node_modules/@ocean/brain/dist/brain/brain-service.js +320 -0
- package/node_modules/@ocean/brain/dist/capture/inbox-sync.js +22 -0
- package/node_modules/@ocean/brain/dist/evidence/verification-report.js +13 -0
- package/node_modules/@ocean/brain/dist/infrastructure/brain/brain-index.js +285 -0
- package/node_modules/@ocean/brain/dist/memory/brain-dump.js +145 -0
- package/node_modules/@ocean/brain/dist/memory/daily-narrative.js +142 -0
- package/node_modules/@ocean/brain/dist/memory/index-sync.js +124 -0
- package/node_modules/@ocean/brain/dist/memory/lesson-activation.js +93 -0
- package/node_modules/@ocean/brain/dist/memory/lesson-learning.js +188 -0
- package/node_modules/@ocean/brain/dist/memory/lessons.js +321 -0
- package/node_modules/@ocean/brain/dist/memory/memory-audit.js +100 -0
- package/node_modules/@ocean/brain/dist/memory/memory-digest.js +49 -0
- package/node_modules/@ocean/brain/dist/memory/memory-harvest.js +345 -0
- package/node_modules/@ocean/brain/dist/memory/memory-paths.js +174 -0
- package/node_modules/@ocean/brain/dist/memory/memory-review.js +278 -0
- package/node_modules/@ocean/brain/dist/memory/memory-trash.js +152 -0
- package/node_modules/@ocean/brain/dist/memory/memory-write.js +216 -0
- package/node_modules/@ocean/brain/dist/memory/model-narrative.js +129 -0
- package/node_modules/@ocean/brain/dist/memory/profile-facts.js +103 -0
- package/node_modules/@ocean/brain/dist/memory/session-promotion.js +61 -0
- package/node_modules/@ocean/brain/dist/memory/session-summary.js +113 -0
- package/node_modules/@ocean/brain/package.json +11 -0
- package/node_modules/@ocean/context/dist/context/context-compression.js +66 -0
- package/node_modules/@ocean/context/dist/context/context-cost.js +587 -0
- package/node_modules/@ocean/context/dist/context/context-ladder.js +363 -0
- package/node_modules/@ocean/context/dist/context/context-packet.js +213 -0
- package/node_modules/@ocean/context/dist/context/context-references.js +255 -0
- package/node_modules/@ocean/context/dist/context/intent-router.js +259 -0
- package/node_modules/@ocean/context/dist/context/resource-injection.js +36 -0
- package/node_modules/@ocean/context/package.json +11 -0
- package/node_modules/@ocean/core/dist/domain/brain/brain-record.js +22 -0
- package/node_modules/@ocean/core/dist/domain/brain/record-scope.js +22 -0
- package/node_modules/@ocean/core/dist/domain/capabilities/browser-contract.js +64 -0
- package/node_modules/@ocean/core/dist/domain/capabilities/capability-contract.js +16 -0
- package/node_modules/@ocean/core/dist/domain/capabilities/capability-manifest.js +72 -0
- package/node_modules/@ocean/core/dist/domain/context/context-validator.js +5 -0
- package/node_modules/@ocean/core/dist/domain/context/context.js +34 -0
- package/node_modules/@ocean/core/dist/domain/context/project-id.js +30 -0
- package/node_modules/@ocean/core/dist/domain/evidence/evidence.js +16 -0
- package/node_modules/@ocean/core/dist/domain/mcp/mcp-contract.js +36 -0
- package/node_modules/@ocean/core/dist/domain/mcp/memory-contract.js +41 -0
- package/node_modules/@ocean/core/dist/domain/ports/brain-index-port.js +7 -0
- package/node_modules/@ocean/core/dist/domain/ports/browser-port.js +8 -0
- package/node_modules/@ocean/core/dist/domain/ports/embedder-port.js +2 -0
- package/node_modules/@ocean/core/dist/domain/ports/platform-ports.js +2 -0
- package/node_modules/@ocean/core/dist/domain/ports/runtime-ports.js +2 -0
- package/node_modules/@ocean/core/dist/domain/ports/session-store-port.js +2 -0
- package/node_modules/@ocean/core/dist/domain/process/process-events.js +5 -0
- package/node_modules/@ocean/core/dist/domain/profiles/profile-distribution.js +19 -0
- package/node_modules/@ocean/core/dist/domain/profiles/profile-policy.js +34 -0
- package/node_modules/@ocean/core/dist/domain/profiles/profile-selection.js +73 -0
- package/node_modules/@ocean/core/dist/domain/profiles/profile-upgrade.js +123 -0
- package/node_modules/@ocean/core/dist/domain/profiles/profile-validator.js +5 -0
- package/node_modules/@ocean/core/dist/domain/profiles/profile.js +218 -0
- package/node_modules/@ocean/core/dist/domain/profiles/runtime-config.js +30 -0
- package/node_modules/@ocean/core/dist/domain/providers/provider-capability.js +28 -0
- package/node_modules/@ocean/core/dist/domain/providers/provider.js +2 -0
- package/node_modules/@ocean/core/dist/domain/redaction/redaction.js +86 -0
- package/node_modules/@ocean/core/dist/domain/runs/agent-tools.js +92 -0
- package/node_modules/@ocean/core/dist/domain/runs/execution-plan.js +71 -0
- package/node_modules/@ocean/core/dist/domain/runs/run-contract.js +38 -0
- package/node_modules/@ocean/core/dist/domain/sessions/entry-contract.js +31 -0
- package/node_modules/@ocean/core/dist/domain/sessions/handoff.js +78 -0
- package/node_modules/@ocean/core/dist/domain/sessions/session.js +58 -0
- package/node_modules/@ocean/core/dist/domain/skills/default-skills.js +29 -0
- package/node_modules/@ocean/core/dist/domain/skills/skill-validator.js +5 -0
- package/node_modules/@ocean/core/dist/domain/skills/skill.js +11 -0
- package/node_modules/@ocean/core/dist/domain/tasks/task-id.js +85 -0
- package/node_modules/@ocean/core/dist/shared/fs-utils.js +212 -0
- package/node_modules/@ocean/core/dist/shared/local-date.js +16 -0
- package/node_modules/@ocean/core/dist/shared/paths.js +324 -0
- package/node_modules/@ocean/core/dist/shared/project-resolution.js +1065 -0
- package/node_modules/@ocean/core/dist/shared/task-reference.js +133 -0
- package/node_modules/@ocean/core/package.json +14 -0
- package/node_modules/@ocean/loop/dist/handoff/handoff-service.js +133 -0
- package/node_modules/@ocean/loop/dist/hooks/lifecycle-hooks.js +15 -0
- package/node_modules/@ocean/loop/dist/hooks/session-end-hook.js +183 -0
- package/node_modules/@ocean/loop/dist/hooks/session-start-hook.js +237 -0
- package/node_modules/@ocean/loop/dist/infrastructure/persistence/session-store.js +690 -0
- package/node_modules/@ocean/loop/dist/infrastructure/persistence/session-validator.js +5 -0
- package/node_modules/@ocean/loop/dist/loops/iteration-graph.js +147 -0
- package/node_modules/@ocean/loop/dist/loops/task-loop-record.js +2 -0
- package/node_modules/@ocean/loop/dist/loops/task-loop.js +281 -0
- package/node_modules/@ocean/loop/dist/operations/memory-knowledge-operations.js +263 -0
- package/node_modules/@ocean/loop/dist/operations/operation-contract.js +227 -0
- package/node_modules/@ocean/loop/dist/operations/operation-scope.js +28 -0
- package/node_modules/@ocean/loop/dist/operations/project-operations.js +93 -0
- package/node_modules/@ocean/loop/dist/operations/record-io.js +65 -0
- package/node_modules/@ocean/loop/dist/operations/record-operations.js +45 -0
- package/node_modules/@ocean/loop/dist/operations/task-linker.js +40 -0
- package/node_modules/@ocean/loop/dist/operations/task-operations.js +279 -0
- package/node_modules/@ocean/loop/dist/operations/write-guard.js +157 -0
- package/node_modules/@ocean/loop/dist/runs/prompt-assembly.js +112 -0
- package/node_modules/@ocean/loop/dist/runs/run-agent.js +425 -0
- package/node_modules/@ocean/loop/dist/runs/run-authorization.js +24 -0
- package/node_modules/@ocean/loop/dist/runs/tool-loop.js +173 -0
- package/node_modules/@ocean/loop/dist/sessions/session-closeout.js +150 -0
- package/node_modules/@ocean/loop/dist/sessions/session-pointer.js +133 -0
- package/node_modules/@ocean/loop/dist/sessions/session-projects.js +26 -0
- package/node_modules/@ocean/loop/dist/sessions/session-retention.js +132 -0
- package/node_modules/@ocean/loop/dist/tasks/archive-tasks.js +210 -0
- package/node_modules/@ocean/loop/dist/tasks/checkpoint-task.js +31 -0
- package/node_modules/@ocean/loop/dist/tasks/claim-task.js +126 -0
- package/node_modules/@ocean/loop/dist/tasks/list-tasks.js +113 -0
- package/node_modules/@ocean/loop/dist/tasks/new-task.js +42 -0
- package/node_modules/@ocean/loop/dist/tasks/renumber-tasks.js +134 -0
- package/node_modules/@ocean/loop/dist/tasks/verification-readiness.js +78 -0
- package/node_modules/@ocean/loop/dist/tasks/verify-task.js +234 -0
- package/node_modules/@ocean/loop/package.json +11 -0
- package/node_modules/@ocean/market/dist/adapters/mcp-adapter.js +64 -0
- package/node_modules/@ocean/market/dist/adapters/owned-directory.js +89 -0
- package/node_modules/@ocean/market/dist/adapters/plugin-adapter.js +39 -0
- package/node_modules/@ocean/market/dist/adapters/skill-adapter.js +32 -0
- package/node_modules/@ocean/market/dist/capability/adapter.js +2 -0
- package/node_modules/@ocean/market/dist/capability/catalog.js +63 -0
- package/node_modules/@ocean/market/dist/capability/content-digest.js +40 -0
- package/node_modules/@ocean/market/dist/capability/registry.js +81 -0
- package/node_modules/@ocean/market/dist/install/default-marketplace.js +47 -0
- package/node_modules/@ocean/market/dist/install/lock.js +34 -0
- package/node_modules/@ocean/market/dist/install/marketplace-service.js +165 -0
- package/node_modules/@ocean/market/dist/mcp/browser-bridge.js +263 -0
- package/node_modules/@ocean/market/dist/mcp/mcp-connection.js +67 -0
- package/node_modules/@ocean/market/dist/mcp/mcp-gateway.js +317 -0
- package/node_modules/@ocean/market/dist/mcp/mcp-launch.js +102 -0
- package/node_modules/@ocean/market/dist/mcp/mcp-runner.js +32 -0
- package/node_modules/@ocean/market/dist/security/description-scan.js +45 -0
- package/node_modules/@ocean/market/dist/security/permissions.js +57 -0
- package/node_modules/@ocean/market/dist/skills/core-skill-sync.js +113 -0
- package/node_modules/@ocean/market/dist/skills/signal-detection.js +84 -0
- package/node_modules/@ocean/market/dist/skills/skill-hub.js +220 -0
- package/node_modules/@ocean/market/package.json +11 -0
- package/node_modules/@ocean/services/dist/browser/browser-service.js +124 -0
- package/node_modules/@ocean/services/dist/browser/browser-session.js +287 -0
- package/node_modules/@ocean/services/dist/browser/browser-task-runner.js +70 -0
- package/node_modules/@ocean/services/dist/doctor/workspace-doctor.js +547 -0
- package/node_modules/@ocean/services/dist/infrastructure/mcp/call-ledger.js +114 -0
- package/node_modules/@ocean/services/dist/infrastructure/mcp/mcp-client.js +162 -0
- package/node_modules/@ocean/services/dist/infrastructure/mcp/obsidian-server.js +251 -0
- package/node_modules/@ocean/services/dist/infrastructure/mcp/ocean-server.js +880 -0
- package/node_modules/@ocean/services/dist/infrastructure/mcp/server-version.js +20 -0
- package/node_modules/@ocean/services/dist/infrastructure/mcp/tool-registry.js +29 -0
- package/node_modules/@ocean/services/dist/obsidian/conflict-log.js +68 -0
- package/node_modules/@ocean/services/dist/obsidian/inbox-promotion.js +80 -0
- package/node_modules/@ocean/services/dist/obsidian/vault-discovery.js +113 -0
- package/node_modules/@ocean/services/dist/obsidian/vault-ingestion.js +77 -0
- package/node_modules/@ocean/services/dist/obsidian/vault-sync.js +73 -0
- package/node_modules/@ocean/services/dist/obsidian/vault-writer.js +75 -0
- package/node_modules/@ocean/services/package.json +11 -0
- package/ocean-marketplace.json +415 -0
- package/package.json +67 -4
- package/skills/core/business-logic/SKILL.md +22 -0
- package/skills/core/catch-up/SKILL.md +17 -0
- package/skills/core/core-thinking/SKILL.md +11 -0
- package/skills/core/design-thinking/SKILL.md +19 -0
- package/skills/core/graft/SKILL.md +156 -0
- package/skills/core/loop/SKILL.md +20 -0
- package/skills/core/session-handoff/SKILL.md +15 -0
- package/skills/core/use-browser/SKILL.md +69 -0
- package/skills/core/verification/SKILL.md +11 -0
- package/skills/index.json +56 -0
- package/templates/README.md +4 -0
- package/templates/profiles/default.json +51 -0
- package/templates/profiles/developer.json +51 -0
- package/templates/profiles/reviewer.json +51 -0
- package/templates/profiles/strategist.json +51 -0
- package/templates/workspace/00-inbox/INBOX.md +7 -0
- package/templates/workspace/00-inbox/candidates/.gitkeep +0 -0
- package/templates/workspace/00-inbox/native/.gitkeep +0 -0
- package/templates/workspace/01-daily/.gitkeep +0 -0
- package/templates/workspace/02-personal/CONFLICTS.md +7 -0
- package/templates/workspace/02-personal/MEMORY.md +15 -0
- package/templates/workspace/02-personal/goals/.gitkeep +0 -0
- package/templates/workspace/02-personal/identity/.gitkeep +0 -0
- package/templates/workspace/02-personal/preferences/.gitkeep +0 -0
- package/templates/workspace/03-professional/.gitkeep +0 -0
- package/templates/workspace/04-projects/PROJECTS.md +5 -0
- package/templates/workspace/04-projects/_template/docs/.gitkeep +0 -0
- package/templates/workspace/04-projects/_template/memory/.gitkeep +0 -0
- package/templates/workspace/04-projects/_template/tasks/.gitkeep +0 -0
- package/templates/workspace/05-knowledge/KNOWLEDGE.md +8 -0
- package/templates/workspace/05-knowledge/decisions/.gitkeep +0 -0
- package/templates/workspace/05-knowledge/lessons/.gitkeep +0 -0
- package/templates/workspace/06-templates/TEMPLATES.md +25 -0
- package/templates/workspace/06-templates/decision.md +8 -0
- package/templates/workspace/06-templates/intelligence.md +32 -0
- package/templates/workspace/06-templates/project-claude.md +48 -0
- package/templates/workspace/06-templates/session.md +38 -0
- package/templates/workspace/06-templates/task.md +42 -0
- package/templates/workspace/MANIFEST.json +51 -0
- package/templates/workspace/bridge/config/CONFIG.md +21 -0
- package/templates/workspace/bridge/config/runtime.json +4 -0
- package/templates/workspace/charter/core.md +104 -0
- package/templates/workspace/charter/policies/README.md +31 -0
- package/templates/workspace/charter/policies/claude-code-context.md +90 -0
- package/templates/workspace/charter/policies/concise-output.md +29 -0
- package/templates/workspace/charter/policies/context.md +91 -0
- package/templates/workspace/charter/policies/contracts/task.md +189 -0
- package/templates/workspace/charter/policies/git.md +60 -0
- package/templates/workspace/charter/policies/graph.md +47 -0
- package/templates/workspace/charter/policies/knowledge.md +33 -0
- package/templates/workspace/charter/policies/lifecycle.md +119 -0
- package/templates/workspace/charter/policies/memory.md +67 -0
- package/templates/workspace/charter/policies/minimal-change.md +43 -0
- package/templates/workspace/charter/policies/models.md +57 -0
- package/templates/workspace/charter/policies/privacy-terms.txt +3 -0
- package/templates/workspace/charter/policies/response.md +39 -0
- package/templates/workspace/charter/policies/skill-observer.md +44 -0
- package/templates/workspace/charter/policies/stack.md +23 -0
- package/templates/workspace/charter/policies/task.md +139 -0
- package/templates/workspace/charter/policies/verification.md +29 -0
- package/templates/workspace/sessions/.gitkeep +0 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { execFile as execFileCallback } from "node:child_process";
|
|
2
|
+
import { promisify } from "node:util";
|
|
3
|
+
import { redactRuntimeText } from "@ocean/core/domain/redaction/redaction.js";
|
|
4
|
+
import { oceanEnv, oceanEnvPair } from "@ocean/core/shared/paths.js";
|
|
5
|
+
const execFile = promisify(execFileCallback);
|
|
6
|
+
const SYSTEM_PROMPT = 'You are a terse session summarizer. Read the evidence and reply with ONLY a JSON object, no prose, no markdown fences: {"workLog":"one line, what happened","decision":"one line or omit","problem":"one line or omit","next":"one line or omit"}. Omit a key entirely if the evidence gives nothing for it. Never invent facts not present in the evidence.';
|
|
7
|
+
function safeText(value, max = 400) {
|
|
8
|
+
return redactRuntimeText(value).replace(/\s+/g, " ").trim().slice(0, max);
|
|
9
|
+
}
|
|
10
|
+
/** Cheap, cost-conscious skip: no point paying for a model call on a trivial session. */
|
|
11
|
+
export function isTrivialSession(events, changedFiles) {
|
|
12
|
+
if (changedFiles.length > 0)
|
|
13
|
+
return false;
|
|
14
|
+
return !events.some((event) => (event.type === "provider_output" || event.type === "text") &&
|
|
15
|
+
event.data.trim().length > 40);
|
|
16
|
+
}
|
|
17
|
+
function buildPrompt(input) {
|
|
18
|
+
const objective = input.events.find((event) => event.type === "user_input" || event.type === "resume_requested");
|
|
19
|
+
const outputs = input.events
|
|
20
|
+
.filter((event) => event.type === "provider_output" ||
|
|
21
|
+
event.type === "text" ||
|
|
22
|
+
event.type === "json")
|
|
23
|
+
.map((event) => safeText(event.data, 300))
|
|
24
|
+
.filter(Boolean)
|
|
25
|
+
.slice(0, 6);
|
|
26
|
+
const errors = input.events
|
|
27
|
+
.filter((event) => event.type === "error" || event.type === "provider_blocked")
|
|
28
|
+
.map((event) => safeText(event.data, 300))
|
|
29
|
+
.slice(0, 3);
|
|
30
|
+
const lines = [
|
|
31
|
+
`Objective: ${safeText(objective?.data ?? input.session.title, 200)}`,
|
|
32
|
+
`Changed files: ${input.changedFiles.length ? input.changedFiles.slice(0, 20).join("; ") : "none"}`,
|
|
33
|
+
outputs.length
|
|
34
|
+
? `Conversation excerpts:\n${outputs.map((line) => `- ${line}`).join("\n")}`
|
|
35
|
+
: "Conversation excerpts: none",
|
|
36
|
+
errors.length
|
|
37
|
+
? `Errors/blocks:\n${errors.map((line) => `- ${line}`).join("\n")}`
|
|
38
|
+
: "",
|
|
39
|
+
input.nextAction
|
|
40
|
+
? `Stated next action: ${safeText(input.nextAction, 200)}`
|
|
41
|
+
: "",
|
|
42
|
+
];
|
|
43
|
+
return lines.filter(Boolean).join("\n");
|
|
44
|
+
}
|
|
45
|
+
export function parseResult(stdout) {
|
|
46
|
+
// --output-format json prints one JSON object, but non-interactive terminal
|
|
47
|
+
// control sequences (e.g. a trailing cursor-show code) can follow it on
|
|
48
|
+
// stdout even when not attached to a TTY — trim to the outermost braces
|
|
49
|
+
// before parsing rather than parsing the whole stream verbatim.
|
|
50
|
+
const start = stdout.indexOf("{");
|
|
51
|
+
const end = stdout.lastIndexOf("}");
|
|
52
|
+
if (start < 0 || end < start)
|
|
53
|
+
return null;
|
|
54
|
+
let envelope;
|
|
55
|
+
try {
|
|
56
|
+
envelope = JSON.parse(stdout.slice(start, end + 1));
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
if (typeof envelope.result !== "string")
|
|
62
|
+
return null;
|
|
63
|
+
const text = envelope.result
|
|
64
|
+
.trim()
|
|
65
|
+
.replace(/^```(?:json)?\s*/i, "")
|
|
66
|
+
.replace(/```\s*$/, "")
|
|
67
|
+
.trim();
|
|
68
|
+
let parsed;
|
|
69
|
+
try {
|
|
70
|
+
parsed = JSON.parse(text);
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
if (!parsed || typeof parsed !== "object")
|
|
76
|
+
return null;
|
|
77
|
+
const value = parsed;
|
|
78
|
+
const narrative = {};
|
|
79
|
+
for (const key of ["workLog", "decision", "problem", "next"]) {
|
|
80
|
+
if (typeof value[key] === "string" && value[key].trim())
|
|
81
|
+
narrative[key] = safeText(value[key], 300);
|
|
82
|
+
}
|
|
83
|
+
return Object.keys(narrative).length ? narrative : null;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Best-effort, cost-conscious human narrative via a cheap headless model call.
|
|
87
|
+
* Returns null on any failure (auth, timeout, parse error) so the caller falls
|
|
88
|
+
* back to the deterministic heuristic in daily-narrative.ts. Never throws.
|
|
89
|
+
*
|
|
90
|
+
* Guarded against recursion: the spawned call carries OCEAN_NARRATIVE_CALL=1,
|
|
91
|
+
* and session-closeout.ts skips calling this again when that flag is already
|
|
92
|
+
* set on the current process (i.e. this IS a narrative-generation session).
|
|
93
|
+
*/
|
|
94
|
+
export async function generateModelNarrative(input) {
|
|
95
|
+
// Opt-in only: unset (tests, CI, a fresh install) means no model call — no
|
|
96
|
+
// network, no auth requirement, no cost, fully deterministic by default.
|
|
97
|
+
if (oceanEnv("MODEL_NARRATIVE") !== "1")
|
|
98
|
+
return null;
|
|
99
|
+
if (oceanEnv("NARRATIVE_CALL") === "1")
|
|
100
|
+
return null;
|
|
101
|
+
if (isTrivialSession(input.events, input.changedFiles))
|
|
102
|
+
return null;
|
|
103
|
+
const prompt = buildPrompt(input);
|
|
104
|
+
try {
|
|
105
|
+
const result = await execFile("claude", [
|
|
106
|
+
"-p",
|
|
107
|
+
prompt,
|
|
108
|
+
"--model",
|
|
109
|
+
"haiku",
|
|
110
|
+
"--output-format",
|
|
111
|
+
"json",
|
|
112
|
+
"--system-prompt",
|
|
113
|
+
SYSTEM_PROMPT,
|
|
114
|
+
"--allowedTools",
|
|
115
|
+
"",
|
|
116
|
+
"--disallowedTools",
|
|
117
|
+
"Bash,Edit,Write,Read,Glob,Grep,NotebookEdit,WebFetch,WebSearch",
|
|
118
|
+
], {
|
|
119
|
+
timeout: 30_000,
|
|
120
|
+
maxBuffer: 65_536,
|
|
121
|
+
env: { ...process.env, ...oceanEnvPair("NARRATIVE_CALL", "1") },
|
|
122
|
+
});
|
|
123
|
+
return parseResult(result.stdout);
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=model-narrative.js.map
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { mkdir, readFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { assertProfileName } from "@ocean/core/domain/profiles/profile.js";
|
|
4
|
+
import { atomicWrite, truncateUtf8, withFileLock, } from "@ocean/core/shared/fs-utils.js";
|
|
5
|
+
import { oceanPath, resolveWithin, SYSTEM_DIR, } from "@ocean/core/shared/paths.js";
|
|
6
|
+
const maxFacts = 100;
|
|
7
|
+
const maxFactBytes = 2_000;
|
|
8
|
+
// The profile name is validated and the path is bounds-checked (including symlinks), so one
|
|
9
|
+
// profile's namespace can never resolve to another file inside or outside the memory root.
|
|
10
|
+
export function profileFactsFile(profile) {
|
|
11
|
+
return resolveWithin(oceanPath(SYSTEM_DIR, "memory", "profiles"), `${assertProfileName(profile)}.json`);
|
|
12
|
+
}
|
|
13
|
+
export async function readProfileFacts(profile) {
|
|
14
|
+
try {
|
|
15
|
+
const facts = JSON.parse(await readFile(profileFactsFile(profile), "utf8"));
|
|
16
|
+
return Array.isArray(facts) ? facts.slice(0, maxFacts) : [];
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
if (error.code === "ENOENT")
|
|
20
|
+
return [];
|
|
21
|
+
throw error;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
// Read-modify-write under the file lock, replaced atomically: concurrent writers to the same
|
|
25
|
+
// profile each see the other's facts, and a crash never leaves a truncated file. `change`
|
|
26
|
+
// returns null to skip the write.
|
|
27
|
+
async function updateProfileFacts(profile, change) {
|
|
28
|
+
const file = profileFactsFile(profile);
|
|
29
|
+
await mkdir(path.dirname(file), { recursive: true, mode: 0o700 });
|
|
30
|
+
await withFileLock(file, async () => {
|
|
31
|
+
const next = change(await readProfileFacts(profile));
|
|
32
|
+
if (next)
|
|
33
|
+
await atomicWrite(file, `${JSON.stringify(next.slice(0, maxFacts), null, 2)}\n`, 0o600);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
export async function writeProfileFact(profile, key, value) {
|
|
37
|
+
if (!/^[a-zA-Z0-9._-]+$/.test(key))
|
|
38
|
+
throw new Error("Fact key must contain only letters, numbers, dot, underscore, or hyphen");
|
|
39
|
+
if (!value.trim() || Buffer.byteLength(value) > maxFactBytes)
|
|
40
|
+
throw new Error("Fact value is empty or exceeds 2000 bytes");
|
|
41
|
+
const fact = {
|
|
42
|
+
key,
|
|
43
|
+
value: value.trim(),
|
|
44
|
+
updatedAt: new Date().toISOString(),
|
|
45
|
+
};
|
|
46
|
+
await updateProfileFacts(profile, (facts) => [
|
|
47
|
+
fact,
|
|
48
|
+
...facts.filter((item) => item.key !== key),
|
|
49
|
+
]);
|
|
50
|
+
return fact;
|
|
51
|
+
}
|
|
52
|
+
export async function deleteProfileFact(profile, key) {
|
|
53
|
+
let deleted = false;
|
|
54
|
+
await updateProfileFacts(profile, (facts) => {
|
|
55
|
+
const remaining = facts.filter((fact) => fact.key !== key);
|
|
56
|
+
deleted = remaining.length !== facts.length;
|
|
57
|
+
return deleted ? remaining : null;
|
|
58
|
+
});
|
|
59
|
+
return deleted;
|
|
60
|
+
}
|
|
61
|
+
export const PROFILE_FACTS_DIGEST_MAX_BYTES = 2_048;
|
|
62
|
+
// A bounded digest of the profile's durable facts for a headless prompt: newest first (by
|
|
63
|
+
// updatedAt, since hand-edited files may not be ordered), whole `- key: value` lines while
|
|
64
|
+
// they fit, and always a pointer to the full set. The whole section stays <= maxBytes; if
|
|
65
|
+
// not even the newest fact fits, it is byte-truncated so at least one fact is visible.
|
|
66
|
+
// `partial` says whether it left anything out (a dropped or byte-truncated fact), in which
|
|
67
|
+
// case the provider must be able to follow the pointer to the store file.
|
|
68
|
+
export function buildProfileFactsDigest(profile, facts, maxBytes = PROFILE_FACTS_DIGEST_MAX_BYTES) {
|
|
69
|
+
if (!facts.length)
|
|
70
|
+
return { text: "", partial: false };
|
|
71
|
+
const time = (fact) => {
|
|
72
|
+
const value = Date.parse(fact.updatedAt);
|
|
73
|
+
return Number.isNaN(value) ? Number.NEGATIVE_INFINITY : value;
|
|
74
|
+
};
|
|
75
|
+
const ordered = [...facts].sort((a, b) => time(b) - time(a));
|
|
76
|
+
const heading = "## Durable profile facts";
|
|
77
|
+
const pointer = (shown) => `(${shown} of ${facts.length} facts, newest first; full set: ocean memory facts ${profile} or ${profileFactsFile(profile)})`;
|
|
78
|
+
// Reserve the pointer's worst case (shown === total) so its size never grows past the budget.
|
|
79
|
+
const reserved = Buffer.byteLength(pointer(facts.length)) + 1;
|
|
80
|
+
const lines = [];
|
|
81
|
+
let used = Buffer.byteLength(heading);
|
|
82
|
+
let whole = 0;
|
|
83
|
+
for (const fact of ordered) {
|
|
84
|
+
const line = `- ${fact.key}: ${String(fact.value).replace(/\s+/g, " ").trim()}`;
|
|
85
|
+
const cost = Buffer.byteLength(line) + 1;
|
|
86
|
+
if (used + cost + reserved <= maxBytes) {
|
|
87
|
+
lines.push(line);
|
|
88
|
+
used += cost;
|
|
89
|
+
whole += 1;
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (!lines.length) {
|
|
93
|
+
const room = maxBytes - used - reserved - 1 - Buffer.byteLength("...");
|
|
94
|
+
lines.push(`${truncateUtf8(line, Math.max(0, room))}...`);
|
|
95
|
+
}
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
text: [heading, ...lines, pointer(lines.length)].join("\n"),
|
|
100
|
+
partial: whole < facts.length,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=profile-facts.js.map
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { redactRuntimeText } from "@ocean/core/domain/redaction/redaction.js";
|
|
4
|
+
import { KNOWLEDGE_DIR, oceanPath } from "@ocean/core/shared/paths.js";
|
|
5
|
+
import { syncMemoryIndexes } from "./index-sync.js";
|
|
6
|
+
const kinds = new Set([
|
|
7
|
+
"architecture",
|
|
8
|
+
"decisions",
|
|
9
|
+
"discoveries",
|
|
10
|
+
"failures",
|
|
11
|
+
"research",
|
|
12
|
+
"results",
|
|
13
|
+
"solutions",
|
|
14
|
+
"references",
|
|
15
|
+
]);
|
|
16
|
+
export async function promoteSessionToKnowledge(sessionId, openStore, target = "knowledge/results", approved = false) {
|
|
17
|
+
if (!approved)
|
|
18
|
+
throw new Error("Session promotion requires explicit approval: use --approve or approved: true");
|
|
19
|
+
const match = /^knowledge\/(\w+)$/.exec(target);
|
|
20
|
+
if (!match || !kinds.has(match[1]))
|
|
21
|
+
throw new Error("Target must be knowledge/<architecture|decisions|discoveries|failures|research|results|solutions|references>");
|
|
22
|
+
const store = await openStore();
|
|
23
|
+
try {
|
|
24
|
+
const session = store.get(sessionId);
|
|
25
|
+
if (!session)
|
|
26
|
+
throw new Error(`Session not found: ${sessionId}`);
|
|
27
|
+
if (session.status !== "completed")
|
|
28
|
+
throw new Error(`Only completed sessions can be promoted: ${session.status}`);
|
|
29
|
+
const events = store.listEvents(sessionId);
|
|
30
|
+
const evidence = events
|
|
31
|
+
.filter((event) => event.type === "evidence")
|
|
32
|
+
.map((event) => event.data)
|
|
33
|
+
.some((data) => /"result"\s*:\s*"proven"/.test(data));
|
|
34
|
+
if (!evidence)
|
|
35
|
+
throw new Error("Session lacks independently recorded successful evidence");
|
|
36
|
+
const input = events.find((event) => event.type === "user_input")?.data ?? "";
|
|
37
|
+
const outputs = events
|
|
38
|
+
.filter((event) => event.type === "provider_output" ||
|
|
39
|
+
event.type === "text" ||
|
|
40
|
+
event.type === "json")
|
|
41
|
+
.map((event) => redactRuntimeText(event.data).trim())
|
|
42
|
+
.filter(Boolean);
|
|
43
|
+
if (!outputs.length)
|
|
44
|
+
throw new Error("Session has no provider output to promote");
|
|
45
|
+
const slug = `${session.provider}-${sessionId.slice(0, 8)}`.replace(/[^a-zA-Z0-9-]+/g, "-");
|
|
46
|
+
const file = path.join(oceanPath(KNOWLEDGE_DIR, match[1], `${slug}.md`));
|
|
47
|
+
await mkdir(path.dirname(file), { recursive: true });
|
|
48
|
+
await writeFile(file, `---\nname: ${slug}\ndescription: Human-approved result from an Ocean session\nmetadata:\n type: session-result\n domain: ${match[1]}\n status: current\n verification: human-approved\n source-session: ${sessionId}\n provider: ${session.provider}\n---\n\n# ${session.provider} review\n\n## Request\n\n${redactRuntimeText(input)}\n\n## Result\n\n${outputs.join("\n\n")}\n`);
|
|
49
|
+
store.appendEvent(sessionId, "knowledge_promoted", JSON.stringify({
|
|
50
|
+
file: path.relative(oceanPath(KNOWLEDGE_DIR), file),
|
|
51
|
+
target,
|
|
52
|
+
approved: true,
|
|
53
|
+
}));
|
|
54
|
+
await syncMemoryIndexes(true);
|
|
55
|
+
return { applied: true, sessionId, file: path.relative(oceanPath(), file) };
|
|
56
|
+
}
|
|
57
|
+
finally {
|
|
58
|
+
store.close();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=session-promotion.js.map
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { redactRuntimeText } from "@ocean/core/domain/redaction/redaction.js";
|
|
5
|
+
import { safeJsonParse } from "@ocean/core/shared/fs-utils.js";
|
|
6
|
+
import { localDate, localMoment } from "@ocean/core/shared/local-date.js";
|
|
7
|
+
import { oceanPath, oceanRoot, SYSTEM_DIR } from "@ocean/core/shared/paths.js";
|
|
8
|
+
const maxSummaryBytes = 12_000;
|
|
9
|
+
function safeText(value, max = 800) {
|
|
10
|
+
return redactRuntimeText(value).replace(/\s+/g, " ").trim().slice(0, max);
|
|
11
|
+
}
|
|
12
|
+
function eventText(events, types, maxItems = 4) {
|
|
13
|
+
return events
|
|
14
|
+
.filter((event) => types.includes(event.type))
|
|
15
|
+
.map((event) => safeText(event.data))
|
|
16
|
+
.filter(Boolean)
|
|
17
|
+
.slice(0, maxItems);
|
|
18
|
+
}
|
|
19
|
+
function lastEvent(events, type) {
|
|
20
|
+
return [...events].reverse().find((event) => event.type === type);
|
|
21
|
+
}
|
|
22
|
+
function renderSessionSummary(input) {
|
|
23
|
+
const { session, events } = input;
|
|
24
|
+
const request = eventText(events, ["user_input", "resume_requested"], 1)[0] ??
|
|
25
|
+
session.title;
|
|
26
|
+
const outputs = eventText(events, ["provider_output", "text", "json"], 4);
|
|
27
|
+
const errors = eventText(events, ["error", "provider_blocked"], 4);
|
|
28
|
+
const evidence = events
|
|
29
|
+
.filter((event) => event.type === "evidence")
|
|
30
|
+
.map((event) => safeJsonParse(event.data))
|
|
31
|
+
.filter((value) => value !== null);
|
|
32
|
+
const proven = evidence
|
|
33
|
+
.filter((value) => value.result === "proven")
|
|
34
|
+
.map((value) => String(value.criterion ?? "verified result"));
|
|
35
|
+
const notProven = evidence
|
|
36
|
+
.filter((value) => value.result !== "proven")
|
|
37
|
+
.map((value) => String(value.criterion ?? value.result ?? "not proven"));
|
|
38
|
+
const processExit = lastEvent(events, "process_exit");
|
|
39
|
+
const exit = input.exitCode ??
|
|
40
|
+
(processExit ? safeJsonParse(processExit.data)?.exitCode : undefined);
|
|
41
|
+
const status = session.status === "completed" && exit === 0 ? "completed" : session.status;
|
|
42
|
+
const nextAction = input.nextAction ??
|
|
43
|
+
session.nextAction ??
|
|
44
|
+
"Review the summary and verify the next action.";
|
|
45
|
+
const lines = [
|
|
46
|
+
"# Session Summary",
|
|
47
|
+
"",
|
|
48
|
+
`- Session: ${session.sessionId}`,
|
|
49
|
+
`- Provider: ${session.provider}`,
|
|
50
|
+
`- Task: ${session.taskId ?? "none"}`,
|
|
51
|
+
`- Profile: ${session.profile}`,
|
|
52
|
+
`- Status: ${status}`,
|
|
53
|
+
`- Working directory: ${safeText(session.workingDirectory, 240)}`,
|
|
54
|
+
"",
|
|
55
|
+
"## Objective",
|
|
56
|
+
"",
|
|
57
|
+
request || "No user objective was captured.",
|
|
58
|
+
"",
|
|
59
|
+
"## What happened",
|
|
60
|
+
"",
|
|
61
|
+
...(outputs.length
|
|
62
|
+
? outputs.map((value) => `- ${value}`)
|
|
63
|
+
: ["- No provider output was captured."]),
|
|
64
|
+
"",
|
|
65
|
+
"## Files changed",
|
|
66
|
+
"",
|
|
67
|
+
...(input.changedFiles?.length
|
|
68
|
+
? input.changedFiles.map((value) => `- ${safeText(value, 240)}`)
|
|
69
|
+
: ["- No changed-file evidence was recorded."]),
|
|
70
|
+
"",
|
|
71
|
+
"## Verification",
|
|
72
|
+
"",
|
|
73
|
+
...(proven.length
|
|
74
|
+
? proven.map((value) => `- PROVEN: ${safeText(value)}`)
|
|
75
|
+
: ["- No independently proven verification recorded."]),
|
|
76
|
+
...(notProven.length
|
|
77
|
+
? notProven.map((value) => `- NOT PROVEN: ${safeText(value)}`)
|
|
78
|
+
: []),
|
|
79
|
+
"",
|
|
80
|
+
"## Problems and limitations",
|
|
81
|
+
"",
|
|
82
|
+
...(errors.length
|
|
83
|
+
? errors.map((value) => `- ${value}`)
|
|
84
|
+
: ["- None recorded."]),
|
|
85
|
+
"",
|
|
86
|
+
"## Next action",
|
|
87
|
+
"",
|
|
88
|
+
safeText(nextAction, 800),
|
|
89
|
+
"",
|
|
90
|
+
"## Retrieval",
|
|
91
|
+
"",
|
|
92
|
+
`- Detailed bounded events: ocean session events ${session.sessionId}`,
|
|
93
|
+
`- Context bytes: ${session.contextBytes}`,
|
|
94
|
+
];
|
|
95
|
+
let content = `${lines.join("\n")}\n`;
|
|
96
|
+
if (Buffer.byteLength(content) > maxSummaryBytes)
|
|
97
|
+
content = `${content.slice(0, maxSummaryBytes - 120)}\n\n- Summary truncated; detailed bounded events remain available by session id.\n`;
|
|
98
|
+
return content;
|
|
99
|
+
}
|
|
100
|
+
export async function writeSessionSummary(input) {
|
|
101
|
+
const date = localDate(localMoment(input.session.createdAt));
|
|
102
|
+
const directory = oceanPath(SYSTEM_DIR, "sessions", "summaries");
|
|
103
|
+
const file = path.join(directory, `${date}-${input.session.sessionId}.md`);
|
|
104
|
+
await mkdir(directory, { recursive: true });
|
|
105
|
+
const content = renderSessionSummary(input);
|
|
106
|
+
await writeFile(file, content, "utf8");
|
|
107
|
+
return {
|
|
108
|
+
summaryPath: path.relative(oceanRoot(), file).split(path.sep).join("/"),
|
|
109
|
+
summaryHash: createHash("sha256").update(content).digest("hex"),
|
|
110
|
+
summaryBytes: Buffer.byteLength(content),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=session-summary.js.map
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
const REQUIRED = /changed files?|verification|security|approval|error|failed|next action/i;
|
|
3
|
+
function boundedByBytes(value, budget) {
|
|
4
|
+
return Buffer.from(value).subarray(0, budget).toString("utf8");
|
|
5
|
+
}
|
|
6
|
+
function unique(lines) {
|
|
7
|
+
return [...new Set(lines.map((line) => line.trim()).filter(Boolean))];
|
|
8
|
+
}
|
|
9
|
+
export function compressContext(input) {
|
|
10
|
+
const originalBytes = Buffer.byteLength(input.content);
|
|
11
|
+
const sourceHash = createHash("sha256").update(input.content).digest("hex");
|
|
12
|
+
if (input.budget <= 0)
|
|
13
|
+
throw new Error("Compression budget must be positive");
|
|
14
|
+
if (originalBytes <= input.budget) {
|
|
15
|
+
return {
|
|
16
|
+
content: input.content,
|
|
17
|
+
sourceId: input.sourceId,
|
|
18
|
+
sourceHash,
|
|
19
|
+
originalBytes,
|
|
20
|
+
compressedBytes: originalBytes,
|
|
21
|
+
method: "none",
|
|
22
|
+
budget: input.budget,
|
|
23
|
+
omittedSections: [],
|
|
24
|
+
recoveryRef: input.sourceId,
|
|
25
|
+
safeToUse: true,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
const lines = input.content.split(/\r?\n/);
|
|
29
|
+
const required = unique(lines.filter((line) => REQUIRED.test(line)));
|
|
30
|
+
const selected = unique([lines[0] ?? "", ...required, lines.at(-1) ?? ""]);
|
|
31
|
+
const content = selected.join("\n");
|
|
32
|
+
const compressedBytes = Buffer.byteLength(content);
|
|
33
|
+
const omittedSections = lines
|
|
34
|
+
.filter((line) => line.trim() && !selected.includes(line.trim()))
|
|
35
|
+
.slice(0, 20)
|
|
36
|
+
.map((line) => line.trim().slice(0, 120));
|
|
37
|
+
if (compressedBytes <= input.budget &&
|
|
38
|
+
required.every((line) => content.includes(line.trim()))) {
|
|
39
|
+
return {
|
|
40
|
+
content,
|
|
41
|
+
sourceId: input.sourceId,
|
|
42
|
+
sourceHash,
|
|
43
|
+
originalBytes,
|
|
44
|
+
compressedBytes,
|
|
45
|
+
method: "ocean-bounded-v1",
|
|
46
|
+
budget: input.budget,
|
|
47
|
+
omittedSections,
|
|
48
|
+
recoveryRef: input.sourceId,
|
|
49
|
+
safeToUse: true,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
const fallback = boundedByBytes(input.content, input.budget);
|
|
53
|
+
return {
|
|
54
|
+
content: fallback,
|
|
55
|
+
sourceId: input.sourceId,
|
|
56
|
+
sourceHash,
|
|
57
|
+
originalBytes,
|
|
58
|
+
compressedBytes: Buffer.byteLength(fallback),
|
|
59
|
+
method: "fallback-original-bounded",
|
|
60
|
+
budget: input.budget,
|
|
61
|
+
omittedSections,
|
|
62
|
+
recoveryRef: input.sourceId,
|
|
63
|
+
safeToUse: false,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=context-compression.js.map
|