@aiwg/cli 2026.10.1 → 2026.10.4
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 +2 -2
- package/agentic/code/providers/capability-matrix.yaml +270 -0
- package/agentic/code/providers/model-capabilities.v1.json +3183 -24
- package/bin/aiwg.mjs +135 -47
- package/dist/src/a2a/codecs.js +9 -0
- package/dist/src/agents/grounding/knowledge-base.js +54 -6
- package/dist/src/artifacts/browser-export.js +6 -0
- package/dist/src/artifacts/checksum-manifest.js +1 -0
- package/dist/src/artifacts/citation-parser.js +173 -92
- package/dist/src/artifacts/citation-table-schema.js +59 -0
- package/dist/src/artifacts/cli.js +57 -18
- package/dist/src/artifacts/corpus-tools/snapshot.js +1 -1
- package/dist/src/artifacts/corpus-tools/vision-extract.js +107 -15
- package/dist/src/artifacts/corpus-views/ref-parser.js +3 -1
- package/dist/src/artifacts/corpus-views/renderers.js +3 -3
- package/dist/src/artifacts/discovery-eval.js +6 -4
- package/dist/src/artifacts/fortemi-core-query-adapter.js +36 -3
- package/dist/src/artifacts/fortemi-core-sync.js +166 -40
- package/dist/src/artifacts/framework-capabilities.js +171 -0
- package/dist/src/artifacts/framework-index-paths.js +73 -0
- package/dist/src/artifacts/framework-source-digest.js +75 -0
- package/dist/src/artifacts/index-builder.js +285 -131
- package/dist/src/artifacts/index-files.js +132 -18
- package/dist/src/artifacts/index-preparation.js +65 -0
- package/dist/src/artifacts/index-refresh.js +576 -0
- package/dist/src/artifacts/index-worker.mjs +9 -0
- package/dist/src/artifacts/prebuilt-build-lock.js +47 -4
- package/dist/src/artifacts/prebuilt-deployment.js +46 -0
- package/dist/src/artifacts/prebuilt-relations.js +80 -0
- package/dist/src/artifacts/query-engine.js +410 -88
- package/dist/src/artifacts/relations-builder.js +168 -0
- package/dist/src/artifacts/relations.js +148 -0
- package/dist/src/artifacts/repair.js +9 -4
- package/dist/src/artifacts/stats.js +5 -2
- package/dist/src/artifacts/types.js +30 -10
- package/dist/src/artifacts/watcher.js +1 -1
- package/dist/src/auth/credential-store.js +2 -1
- package/dist/src/catalog/cli.d.mts +5 -0
- package/dist/src/channel/manager.d.mts +20 -0
- package/dist/src/channel/manager.mjs +78 -12
- package/dist/src/cli/child-process-result.js +40 -0
- package/dist/src/cli/command-log.js +2 -3
- package/dist/src/cli/env.js +38 -16
- package/dist/src/cli/flag-parsing.js +236 -0
- package/dist/src/cli/handlers/artifacts.js +3 -0
- package/dist/src/cli/handlers/auth.js +3 -0
- package/dist/src/cli/handlers/decision.js +218 -5
- package/dist/src/cli/handlers/diagnose.js +13 -5
- package/dist/src/cli/handlers/effect.js +4 -2
- package/dist/src/cli/handlers/evidence.js +3 -0
- package/dist/src/cli/handlers/feedback.js +14 -5
- package/dist/src/cli/handlers/help.js +1 -0
- package/dist/src/cli/handlers/index.js +3 -1
- package/dist/src/cli/handlers/init.js +248 -30
- package/dist/src/cli/handlers/lint.js +5 -0
- package/dist/src/cli/handlers/mc.js +23 -0
- package/dist/src/cli/handlers/models.js +169 -10
- package/dist/src/cli/handlers/ralph-launcher.js +2 -0
- package/dist/src/cli/handlers/ralph.js +3 -0
- package/dist/src/cli/handlers/refresh.js +28 -0
- package/dist/src/cli/handlers/regenerate.js +14 -0
- package/dist/src/cli/handlers/resource-versions.js +3 -0
- package/dist/src/cli/handlers/rules.js +195 -0
- package/dist/src/cli/handlers/run.js +4 -0
- package/dist/src/cli/handlers/runtime-info.js +25 -11
- package/dist/src/cli/handlers/script-runner.js +19 -8
- package/dist/src/cli/handlers/session.js +406 -62
- package/dist/src/cli/handlers/sessions.js +243 -76
- package/dist/src/cli/handlers/setup-manifest.js +474 -79
- package/dist/src/cli/handlers/setup.js +180 -39
- package/dist/src/cli/handlers/steward.js +11 -0
- package/dist/src/cli/handlers/subcommands.js +60 -3
- package/dist/src/cli/handlers/team.js +18 -8
- package/dist/src/cli/handlers/uhp.js +3 -0
- package/dist/src/cli/handlers/use.js +307 -55
- package/dist/src/cli/handlers/utilities.js +125 -26
- package/dist/src/cli/handlers/version.js +8 -0
- package/dist/src/cli/prompt-utils.js +72 -0
- package/dist/src/cli/provider-resolution.js +11 -0
- package/dist/src/cli/router.js +15 -1
- package/dist/src/cli/services/deployment-verification.js +19 -9
- package/dist/src/cli/services/provider-prepare-coordinator.js +24 -0
- package/dist/src/cli/skill-usage.js +2 -3
- package/dist/src/config/aiwg-config.js +349 -35
- package/dist/src/config/cli.js +256 -23
- package/dist/src/config/decision-config.js +106 -0
- package/dist/src/config/dispatch-thresholds-runtime.d.mts +8 -0
- package/dist/src/config/dispatch-thresholds-runtime.mjs +38 -0
- package/dist/src/config/gitignore.js +50 -0
- package/dist/src/config/index-graph-overrides.js +36 -0
- package/dist/src/config/project-artifacts-health.d.mts +37 -0
- package/dist/src/config/project-artifacts-health.mjs +14 -3
- package/dist/src/config/project-artifacts-runtime.d.mts +16 -0
- package/dist/src/config/user-config-dir.d.mts +9 -0
- package/dist/src/config/user-config.js +38 -11
- package/dist/src/config/user-registry.js +23 -15
- package/dist/src/config/user-state.js +7 -0
- package/dist/src/decision/adapters/jev.js +75 -27
- package/dist/src/decision/ask.js +203 -43
- package/dist/src/decision/context-live-qualification.js +2 -2
- package/dist/src/decision/driver.js +14 -7
- package/dist/src/decision/ensemble/aggregate.js +23 -10
- package/dist/src/decision/ensemble-study/multifact-study.js +6 -2
- package/dist/src/decision/entry.js +25 -6
- package/dist/src/decision/graph-live-qualification.js +1 -1
- package/dist/src/decision/graph-run.js +9 -0
- package/dist/src/decision/heldout/collector.js +15 -14
- package/dist/src/decision/heldout/contract.js +30 -7
- package/dist/src/decision/index.js +1 -0
- package/dist/src/decision/interop.js +60 -8
- package/dist/src/decision/jev-credentials.js +15 -1
- package/dist/src/decision/ledger.js +942 -0
- package/dist/src/decision/offload-activation.js +137 -0
- package/dist/src/decision/offload.js +550 -0
- package/dist/src/decision/qualification/load.js +4 -6
- package/dist/src/decision/savings.js +28 -0
- package/dist/src/decision/validate.js +6 -3
- package/dist/src/effects/dispatch-verifier.js +252 -0
- package/dist/src/effects/index.js +1 -0
- package/dist/src/effects/types.js +5 -1
- package/dist/src/effects/verifiers/git.js +2 -1
- package/dist/src/effects/verifiers/tracker.js +26 -14
- package/dist/src/extensions/commands/definitions.js +19 -0
- package/dist/src/extensions/project-local-remove.js +36 -1
- package/dist/src/features/installer.js +2 -2
- package/dist/src/flow/graph-metadata.js +5 -0
- package/dist/src/gates/providers/loader.js +64 -18
- package/dist/src/installation/manager-command.d.mts +18 -0
- package/dist/src/installation/manager-command.mjs +15 -3
- package/dist/src/installation/manager.d.mts +49 -0
- package/dist/src/installation/manager.mjs +95 -5
- package/dist/src/issues/cli.js +4 -4
- package/dist/src/issues/local.js +24 -5
- package/dist/src/jobs/runner.js +1 -1
- package/dist/src/lint/cli.js +27 -1
- package/dist/src/lint/loader.js +2 -1
- package/dist/src/lint/reporters.js +25 -1
- package/dist/src/lint/rule-activation.js +43 -0
- package/dist/src/lint/runner.js +137 -62
- package/dist/src/mcp/adapters/codex-runtime.js +366 -56
- package/dist/src/mcp/claude-install.d.mts +4 -0
- package/dist/src/mcp/claude-install.mjs +41 -0
- package/dist/src/mcp/cli.d.mts +1 -0
- package/dist/src/mcp/cli.mjs +620 -85
- package/dist/src/mcp/config-file.d.mts +28 -0
- package/dist/src/mcp/config-file.mjs +279 -0
- package/dist/src/mcp/config-layers.d.mts +36 -0
- package/dist/src/mcp/config-layers.mjs +348 -0
- package/dist/src/mcp/credentials.d.mts +51 -0
- package/dist/src/mcp/credentials.mjs +484 -0
- package/dist/src/mcp/grok-build-config.d.mts +6 -0
- package/dist/src/mcp/grok-build-config.mjs +17 -27
- package/dist/src/mcp/helpers.mjs +109 -4
- package/dist/src/mcp/muse-native-config.d.mts +13 -0
- package/dist/src/mcp/muse-native-config.mjs +1 -0
- package/dist/src/mcp/omp-config.d.mts +4 -0
- package/dist/src/mcp/omp-config.mjs +50 -29
- package/dist/src/mcp/profiles.js +97 -23
- package/dist/src/mcp/profiles.mjs +99 -27
- package/dist/src/mcp/registry.js +248 -131
- package/dist/src/mcp/registry.mjs +169 -100
- package/dist/src/mcp/server-config.d.mts +3 -0
- package/dist/src/mcp/server-config.mjs +89 -0
- package/dist/src/mcp/server.mjs +127 -82
- package/dist/src/mcp/test-simple.mjs +2 -1
- package/dist/src/mcp/toml-editor.d.mts +4 -0
- package/dist/src/mcp/toml-string.d.mts +1 -0
- package/dist/src/mcp/toml-string.mjs +9 -0
- package/dist/src/mcp/toml-strip-mcp.d.mts +1 -0
- package/dist/src/mcp/toml-strip-mcp.mjs +135 -0
- package/dist/src/mcp/tool-filters.d.mts +46 -0
- package/dist/src/mcp/tool-filters.mjs +357 -0
- package/dist/src/mcp/tools/agentic-sandbox.mjs +3 -1
- package/dist/src/mcp/tools/decision.mjs +22 -3
- package/dist/src/mcp/tools/discovery.mjs +62 -55
- package/dist/src/mcp/tools/orchestration.mjs +50 -2
- package/dist/src/mcp/tools/subsystems.mjs +39 -8
- package/dist/src/mcp/tools/worker-invoke.mjs +2856 -0
- package/dist/src/mcp/tools/worker-shell-control.mjs +289 -0
- package/dist/src/mcp/tools/worker-stdin-runtime.mjs +79 -0
- package/dist/src/memory/project-registry.js +2 -2
- package/dist/src/mission-protocol/codecs.js +647 -1
- package/dist/src/mission-protocol/types.js +110 -0
- package/dist/src/mission-protocol/worker-status.js +2 -0
- package/dist/src/models/config-loader.js +76 -14
- package/dist/src/models/grok-build-models.js +93 -41
- package/dist/src/models/model-capabilities.v1.json +3183 -24
- package/dist/src/models/model-discovery.js +931 -67
- package/dist/src/models/provider-policy.js +719 -11
- package/dist/src/models/qualification-digest.d.mts +2 -0
- package/dist/src/models/qualification-digest.mjs +17 -0
- package/dist/src/models/resolver.js +261 -0
- package/dist/src/models/worker-direct-readiness.js +550 -0
- package/dist/src/models/worker-dispatch-offer.js +169 -0
- package/dist/src/models/worker-health-readiness.js +144 -0
- package/dist/src/models/worker-installation.d.mts +39 -0
- package/dist/src/models/worker-installation.mjs +986 -0
- package/dist/src/models/wrapper-route.js +18 -0
- package/dist/src/ops/registry.js +9 -14
- package/dist/src/plugins/standalone-packager.js +4 -3
- package/dist/src/process/bounded-child-process.d.mts +84 -0
- package/dist/src/process/bounded-child-process.mjs +430 -0
- package/dist/src/process/cli-command.d.mts +16 -0
- package/dist/src/process/cli-command.mjs +75 -0
- package/dist/src/process/signal-child.d.mts +6 -0
- package/dist/src/process/signal-child.mjs +7 -0
- package/dist/src/providers/capability-matrix.js +8 -0
- package/dist/src/providers/capability-matrix.yaml +270 -0
- package/dist/src/providers/deployed-skill-roots.js +20 -0
- package/dist/src/providers/grok-build-acp.js +3 -2
- package/dist/src/providers/grok-build-headless.js +53 -23
- package/dist/src/providers/grok-build-inspect.js +1 -0
- package/dist/src/providers/omp-agent.d.mts +8 -0
- package/dist/src/providers/omp-diagnostics.d.mts +1 -0
- package/dist/src/providers/omp-paths.d.mts +13 -0
- package/dist/src/providers/provider-definitions.js +9 -1
- package/dist/src/providers/provider-definitions.mjs +9 -2
- package/dist/src/providers/skill-ownership.d.mts +9 -0
- package/dist/src/providers/skill-ownership.mjs +88 -0
- package/dist/src/rules/activation.d.mts +21 -0
- package/dist/src/rules/activation.mjs +62 -0
- package/dist/src/rules/inline-budget.d.mts +26 -0
- package/dist/src/rules/inline-budget.mjs +66 -0
- package/dist/src/rules/inventory.js +129 -0
- package/dist/src/rules/pin-state.js +73 -0
- package/dist/src/rules/pins.d.mts +14 -0
- package/dist/src/rules/pins.mjs +112 -0
- package/dist/src/rules/rule-frontmatter.schema.json +197 -0
- package/dist/src/serve/executor-registry.js +16 -24
- package/dist/src/serve/fleet-mission-conductor.js +9 -0
- package/dist/src/serve/mission-conductor.js +47 -12
- package/dist/src/serve/shared-host-scheduler.js +2 -0
- package/dist/src/serve/worker-invocation.js +558 -0
- package/dist/src/serve/worker-stdin-frame.d.mts +10 -0
- package/dist/src/serve/worker-stdin-frame.mjs +107 -0
- package/dist/src/sessions/adapter-registry.js +49 -0
- package/dist/src/sessions/adapters/claude.js +39 -54
- package/dist/src/sessions/adapters/codex.js +82 -67
- package/dist/src/sessions/adapters/copilot.js +4 -4
- package/dist/src/sessions/adapters/cursor.js +40 -57
- package/dist/src/sessions/adapters/deepseek-harness.js +15 -12
- package/dist/src/sessions/adapters/factory.js +31 -27
- package/dist/src/sessions/adapters/generic.js +43 -9
- package/dist/src/sessions/adapters/grok-build.js +11 -11
- package/dist/src/sessions/adapters/grokbot-locator.js +111 -0
- package/dist/src/sessions/adapters/grokbot.js +434 -24
- package/dist/src/sessions/adapters/hermes.js +27 -29
- package/dist/src/sessions/adapters/muse-workspace-scan.js +128 -0
- package/dist/src/sessions/adapters/muse.js +200 -104
- package/dist/src/sessions/adapters/omp.js +28 -14
- package/dist/src/sessions/adapters/openclaw.js +89 -79
- package/dist/src/sessions/adapters/opencode.js +27 -24
- package/dist/src/sessions/adapters/openhuman.js +18 -60
- package/dist/src/sessions/adapters/pi.js +30 -14
- package/dist/src/sessions/adapters/warp.js +3 -3
- package/dist/src/sessions/adapters/windsurf.js +19 -48
- package/dist/src/sessions/batch-contracts.js +25 -5
- package/dist/src/sessions/batch-import.js +72 -51
- package/dist/src/sessions/candidates.js +47 -11
- package/dist/src/sessions/contracts.js +75 -2
- package/dist/src/sessions/coverage-preflight.js +134 -0
- package/dist/src/sessions/discovery.js +3 -0
- package/dist/src/sessions/export-plan.js +4 -3
- package/dist/src/sessions/grok-build-cli.js +67 -5
- package/dist/src/sessions/import-exclusions.js +72 -0
- package/dist/src/sessions/import-lease.js +34 -18
- package/dist/src/sessions/import-limits.js +37 -0
- package/dist/src/sessions/importer.js +84 -46
- package/dist/src/sessions/index.js +2 -0
- package/dist/src/sessions/lifecycle.js +45 -0
- package/dist/src/sessions/policy.js +133 -25
- package/dist/src/sessions/readers.js +106 -53
- package/dist/src/sessions/refresh.js +106 -0
- package/dist/src/sessions/repository.js +199 -63
- package/dist/src/sessions/workspace-discovery.js +315 -88
- package/dist/src/sessions/workspace-matching.js +107 -0
- package/dist/src/skills/adapters/clawhub.js +10 -8
- package/dist/src/skills/adapters/openclaw.js +10 -7
- package/dist/src/skills/importer.js +1 -0
- package/dist/src/smiths/context-pipeline/aiwg-md.js +11 -0
- package/dist/src/smiths/context-pipeline/claude-hook.js +3 -26
- package/dist/src/smiths/context-pipeline/finalization.js +6 -5
- package/dist/src/smiths/context-pipeline/generator.js +21 -4
- package/dist/src/smiths/context-pipeline/parallelism-section.js +195 -14
- package/dist/src/smiths/context-pipeline/workspace-context.js +116 -9
- package/dist/src/smiths/hook-bridge/codex-translator.js +6 -5
- package/dist/src/smiths/mcpsmith/example.js +1 -1
- package/dist/src/smiths/mcpsmith/generator.js +1 -1
- package/dist/src/smiths/toolsmith/runtime-discovery.d.mts +10 -0
- package/dist/src/smiths/toolsmith/runtime-discovery.mjs +85 -31
- package/dist/src/storage/backends/fs.js +18 -76
- package/dist/src/storage/backends/logseq.js +68 -7
- package/dist/src/storage/backends/obsidian.js +1 -0
- package/dist/src/storage/fortemi-qualification-receipt.js +2 -2
- package/dist/src/testing/generators/test-code-generator.js +57 -30
- package/dist/src/tracker/forge-http.js +2 -1
- package/dist/src/uhp/client.js +11 -1
- package/dist/src/uhp/mission.js +5 -0
- package/dist/src/update/checker.d.mts +2 -0
- package/dist/src/update/checker.mjs +5 -5
- package/dist/src/update/notifier.mjs +54 -2
- package/dist/src/update/service.d.mts +22 -0
- package/dist/src/utils/contained-filesystem.d.mts +37 -0
- package/dist/src/utils/contained-filesystem.mjs +683 -0
- package/dist/src/utils/temporary-directory.js +36 -0
- package/dist/src/writing/example-generator.js +1 -1
- package/dist/src/writing/fidelity.js +18 -1
- package/package.json +32 -2
- package/schemas/mission-v1.schema.json +2429 -0
- package/schemas/models/model-catalog.v1.schema.json +301 -0
- package/schemas/models/model-config-compatibility.v1.schema.json +281 -0
- package/schemas/models/model-policy.v1.schema.json +14 -0
- package/schemas/models/provider-model-capabilities.v1.schema.json +1072 -0
- package/tools/_resolve-impl.mjs +39 -2
- package/tools/agents/deploy-agents.mjs +64 -23
- package/tools/agents/providers/base.mjs +153 -166
- package/tools/agents/providers/claude.mjs +8 -24
- package/tools/agents/providers/codex.mjs +18 -11
- package/tools/agents/providers/cursor.mjs +19 -18
- package/tools/agents/providers/grok-build.mjs +3 -1
- package/tools/agents/providers/grokbot.mjs +11 -12
- package/tools/agents/providers/hermes.mjs +62 -49
- package/tools/agents/providers/omp.mjs +5 -2
- package/tools/agents/providers/openclaw-translator.mjs +19 -5
- package/tools/agents/providers/openclaw.mjs +9 -4
- package/tools/agents/providers/pi.mjs +5 -0
- package/tools/agents/providers/provider-prepare-channel.mjs +5 -0
- package/tools/agents/providers/provider-prepare-coordinator.mjs +247 -0
- package/tools/agents/providers/provider-prepare-worker.mjs +84 -0
- package/tools/agents/providers/rule-delivery.mjs +1270 -0
- package/tools/agents/providers/warp.mjs +20 -26
- package/tools/cli/decision-offload-report.mjs +40 -0
- package/tools/cli/workspace-status.mjs +862 -0
- package/tools/plugin/package-plugins.mjs +186 -8
- package/tools/plugin/plugin-links.mjs +114 -0
- package/tools/providers/antigravity-transport.mjs +3 -1
- package/tools/providers/deepseek-harness-transport.mjs +360 -0
- package/tools/providers/omp-transport.mjs +194 -0
- package/tools/ralph-external/lib/claude-adapter.mjs +389 -0
- package/tools/ralph-external/lib/codex-adapter.mjs +432 -0
- package/tools/ralph-external/lib/consecutive-failure-circuit-breaker.mjs +1748 -0
- package/tools/ralph-external/lib/deepseek-harness-adapter.mjs +397 -0
- package/tools/ralph-external/lib/factory-adapter.mjs +503 -0
- package/tools/ralph-external/lib/launcher-recovery-evidence.mjs +55 -0
- package/tools/ralph-external/lib/muse-adapter.mjs +364 -0
- package/tools/ralph-external/lib/omp-adapter.mjs +315 -0
- package/tools/ralph-external/lib/opencode-adapter.mjs +575 -0
- package/tools/ralph-external/lib/openhuman-adapter.mjs +75 -0
- package/tools/ralph-external/lib/pi-adapter.mjs +329 -0
- package/tools/ralph-external/lib/provider-adapter.mjs +748 -0
- package/tools/ralph-external/lib/recovery-probe.mjs +72 -0
- package/tools/ralph-external/lib/session-environment.mjs +28 -0
- package/tools/ralph-external/lib/systemd-client.mjs +49 -0
- package/tools/ralph-external/lib/worker-health.mjs +439 -0
- package/tools/ralph-external/lib/worker-isolation.mjs +717 -0
- package/tools/ralph-external/lib/worker-overflow.mjs +50 -0
- package/tools/ralph-external/process-monitor.mjs +1017 -0
- package/tools/ralph-external/session-launcher.mjs +5057 -0
- package/tools/scripts/resource-preflight.mjs +541 -0
- package/tools/skills/deploy-skills-codex.mjs +2 -1
- package/vscode-extension/schemas/aiwg.config.v1.json +2916 -0
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import { requireFeaturePackage } from '../features/runtime.js';
|
|
2
2
|
import { CandidateReviewReceiptSchema, DeletionReceiptSchema, IntelligenceCandidateSchema, PromotionDependencyDecisionSchema, PromotionReceiptSchema, SessionContractError, sha256, } from './contracts.js';
|
|
3
3
|
import { coverageFromBatchRun, } from './batch-contracts.js';
|
|
4
|
-
import { redactSessionText, sanitizeNativeExtensions } from './policy.js';
|
|
4
|
+
import { redactSessionText, redactSessionValue, sanitizeSessionEvent, sanitizeNativeExtensions } from './policy.js';
|
|
5
|
+
import { effectiveSessionLifecycle } from './lifecycle.js';
|
|
5
6
|
import { deriveSessionAnalytics, } from './analytics.js';
|
|
6
7
|
const POLICY_PROVIDER_MIGRATION = 'policy-provider-identity:v2';
|
|
7
8
|
const EVENT_ORIGIN_INTENT_MIGRATION = 'event-origin-intent:v1';
|
|
9
|
+
const VISIBLE_SESSION_PREDICATE = `s.lifecycle != 'tombstoned' AND EXISTS (
|
|
10
|
+
SELECT 1 FROM session_events e
|
|
11
|
+
JOIN import_runs r ON r.import_run_id=e.import_run_id
|
|
12
|
+
WHERE e.session_id=s.session_id AND r.status='committed'
|
|
13
|
+
)`;
|
|
8
14
|
export class SessionRepository {
|
|
9
15
|
db;
|
|
10
16
|
constructor(path = ':memory:') {
|
|
@@ -119,6 +125,12 @@ export class SessionRepository {
|
|
|
119
125
|
ON sessions(workspace_id, source_id, lifecycle);
|
|
120
126
|
CREATE INDEX IF NOT EXISTS idx_event_session_sequence
|
|
121
127
|
ON session_events(session_id, sequence_no);
|
|
128
|
+
CREATE INDEX IF NOT EXISTS idx_event_source_run
|
|
129
|
+
ON session_events(source_id, import_run_id);
|
|
130
|
+
CREATE INDEX IF NOT EXISTS idx_event_import_run_session
|
|
131
|
+
ON session_events(import_run_id, session_id);
|
|
132
|
+
CREATE INDEX IF NOT EXISTS idx_session_analytics_session
|
|
133
|
+
ON session_analytics_facts(session_id);
|
|
122
134
|
CREATE INDEX IF NOT EXISTS idx_session_analytics_scope
|
|
123
135
|
ON session_analytics_facts(
|
|
124
136
|
workspace_id, category, provider, status, occurred_at, fact_id
|
|
@@ -126,6 +138,9 @@ export class SessionRepository {
|
|
|
126
138
|
CREATE VIRTUAL TABLE IF NOT EXISTS session_event_fts USING fts5(
|
|
127
139
|
event_id UNINDEXED, searchable_text, tokenize='unicode61'
|
|
128
140
|
);
|
|
141
|
+
-- FTS5 stores event_id in c0. A covering index checks identity/rowid
|
|
142
|
+
-- alignment without reading searchable text or event JSON.
|
|
143
|
+
CREATE INDEX IF NOT EXISTS idx_fts_event_id ON session_event_fts_content(c0);
|
|
129
144
|
`);
|
|
130
145
|
const deletionReceiptColumns = this.db.prepare('PRAGMA table_info(deletion_receipts)').all().map((row) => String(row.name));
|
|
131
146
|
if (!deletionReceiptColumns.includes('workspace_id')) {
|
|
@@ -149,48 +164,79 @@ export class SessionRepository {
|
|
|
149
164
|
CREATE INDEX IF NOT EXISTS idx_mutation_audit_workspace
|
|
150
165
|
ON mutation_audit(workspace_id, occurred_at, operation_id)
|
|
151
166
|
;
|
|
167
|
+
CREATE INDEX IF NOT EXISTS idx_import_runs_batch
|
|
168
|
+
ON import_runs(batch_run_id);
|
|
152
169
|
CREATE INDEX IF NOT EXISTS idx_batch_import_workspace
|
|
153
170
|
ON batch_import_runs(workspace_id, updated_at, batch_run_id)
|
|
154
171
|
`);
|
|
172
|
+
this.initializeAnalyticsVerification();
|
|
155
173
|
this.alignSessionFtsRowids();
|
|
156
174
|
this.migrateSessionPolicyAndProviderIdentity();
|
|
157
175
|
this.migrateEventOriginAndIntent();
|
|
158
176
|
this.alignSessionAnalytics();
|
|
159
177
|
}
|
|
178
|
+
initializeAnalyticsVerification() {
|
|
179
|
+
// Invalidate verification even for writes from another connection. Ordinary
|
|
180
|
+
// repository mutations maintain analytics in the same transaction below.
|
|
181
|
+
this.db.transaction(() => {
|
|
182
|
+
this.db.prepare('INSERT OR IGNORE INTO session_catalog_meta(key, value) VALUES (?, ?)').run('consistency:analytics:v1', 'dirty');
|
|
183
|
+
for (const table of [
|
|
184
|
+
'session_events', 'session_analytics_facts', 'sessions', 'session_sources', 'import_runs',
|
|
185
|
+
]) {
|
|
186
|
+
for (const operation of ['INSERT', 'UPDATE', 'DELETE']) {
|
|
187
|
+
this.db.exec(`
|
|
188
|
+
CREATE TRIGGER IF NOT EXISTS consistency_${table}_${operation.toLowerCase()}
|
|
189
|
+
AFTER ${operation} ON ${table}
|
|
190
|
+
BEGIN
|
|
191
|
+
UPDATE session_catalog_meta SET value='dirty'
|
|
192
|
+
WHERE key='consistency:analytics:v1' AND value!='dirty';
|
|
193
|
+
END;
|
|
194
|
+
`);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
})();
|
|
198
|
+
}
|
|
199
|
+
analyticsVerified() {
|
|
200
|
+
return this.db.prepare('SELECT value FROM session_catalog_meta WHERE key=?').get('consistency:analytics:v1')?.value === 'verified';
|
|
201
|
+
}
|
|
202
|
+
markAnalyticsVerified() {
|
|
203
|
+
this.db.prepare('UPDATE session_catalog_meta SET value=? WHERE key=?').run('verified', 'consistency:analytics:v1');
|
|
204
|
+
}
|
|
205
|
+
maintainedAnalyticsTransaction(mutate) {
|
|
206
|
+
return this.db.transaction(() => {
|
|
207
|
+
const verified = this.analyticsVerified();
|
|
208
|
+
const result = mutate();
|
|
209
|
+
// A scoped mutation must not hide pre-existing damage elsewhere.
|
|
210
|
+
if (verified)
|
|
211
|
+
this.markAnalyticsVerified();
|
|
212
|
+
return result;
|
|
213
|
+
});
|
|
214
|
+
}
|
|
160
215
|
alignSessionAnalytics() {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
const factSessions = Number(this.db.prepare('SELECT COUNT(DISTINCT session_id) AS count FROM session_analytics_facts').get()?.count ?? 0);
|
|
167
|
-
const sourceSessions = Number(this.db.prepare(`SELECT COUNT(DISTINCT e.session_id) AS count
|
|
168
|
-
FROM session_events e
|
|
169
|
-
JOIN import_runs r ON r.import_run_id=e.import_run_id
|
|
170
|
-
JOIN sessions s ON s.session_id=e.session_id
|
|
171
|
-
WHERE r.status='committed' AND s.lifecycle!='tombstoned'`).get()?.count ?? 0);
|
|
172
|
-
if (eventCount === 0 || factSessions === sourceSessions)
|
|
173
|
-
return;
|
|
174
|
-
this.rebuildAnalytics();
|
|
216
|
+
this.db.transaction(() => {
|
|
217
|
+
if (this.analyticsVerified())
|
|
218
|
+
return;
|
|
219
|
+
this.rebuildAnalytics();
|
|
220
|
+
})();
|
|
175
221
|
}
|
|
176
222
|
alignSessionFtsRowids() {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
223
|
+
this.db.transaction(() => {
|
|
224
|
+
const eventCount = Number(this.db.prepare('SELECT COUNT(*) AS count FROM session_events').get()?.count ?? 0);
|
|
225
|
+
const ftsCount = Number(this.db.prepare('SELECT COUNT(*) AS count FROM session_event_fts_content').get()?.count ?? 0);
|
|
226
|
+
const mismatch = this.db.prepare(`SELECT 1 AS mismatch
|
|
227
|
+
FROM session_event_fts_content f
|
|
228
|
+
LEFT JOIN session_events e ON e.event_id=f.c0
|
|
229
|
+
WHERE e.rowid IS NULL OR e.rowid!=f.id
|
|
230
|
+
LIMIT 1`).get();
|
|
231
|
+
if (eventCount === ftsCount && !mismatch)
|
|
232
|
+
return;
|
|
186
233
|
this.db.exec('DELETE FROM session_event_fts');
|
|
187
234
|
this.db.exec(`
|
|
188
235
|
INSERT INTO session_event_fts(rowid, event_id, searchable_text)
|
|
189
236
|
SELECT rowid, event_id, json_extract(data, '$.searchableText')
|
|
190
237
|
FROM session_events
|
|
191
238
|
`);
|
|
192
|
-
});
|
|
193
|
-
rebuild();
|
|
239
|
+
})();
|
|
194
240
|
}
|
|
195
241
|
migrateSessionPolicyAndProviderIdentity() {
|
|
196
242
|
this.runCatalogMigration(POLICY_PROVIDER_MIGRATION, () => {
|
|
@@ -326,6 +372,7 @@ export class SessionRepository {
|
|
|
326
372
|
transaction();
|
|
327
373
|
}
|
|
328
374
|
emitMutation(input) {
|
|
375
|
+
input = redactSessionValue(input).value;
|
|
329
376
|
const unsigned = {
|
|
330
377
|
contractVersion: '1.0.0',
|
|
331
378
|
...input,
|
|
@@ -430,7 +477,17 @@ export class SessionRepository {
|
|
|
430
477
|
};
|
|
431
478
|
}
|
|
432
479
|
applyImport(batch, checkpoint, publish = true) {
|
|
433
|
-
|
|
480
|
+
// Guard callers that submit normalized batches directly as well as adapters.
|
|
481
|
+
batch = redactSessionValue({
|
|
482
|
+
...batch,
|
|
483
|
+
source: { ...batch.source, extensions: sanitizeNativeExtensions(batch.source.extensions).value },
|
|
484
|
+
sessions: batch.sessions.map((session) => ({
|
|
485
|
+
...session, extensions: sanitizeSessionExtensions(session.extensions, session.provider),
|
|
486
|
+
})),
|
|
487
|
+
events: batch.events.map(sanitizeSessionEvent),
|
|
488
|
+
}).value;
|
|
489
|
+
checkpoint = redactSessionValue(checkpoint).value;
|
|
490
|
+
const apply = this.maintainedAnalyticsTransaction(() => {
|
|
434
491
|
const existing = this.db.prepare('SELECT outcome, counts, checkpoint FROM import_receipts WHERE import_run_id = ?').get(batch.run.importRunId);
|
|
435
492
|
if (existing) {
|
|
436
493
|
const counts = JSON.parse(String(existing.counts));
|
|
@@ -536,7 +593,7 @@ export class SessionRepository {
|
|
|
536
593
|
return apply();
|
|
537
594
|
}
|
|
538
595
|
commitStagedImports(sourceId, parserVersion) {
|
|
539
|
-
const commit = this.
|
|
596
|
+
const commit = this.maintainedAnalyticsTransaction(() => {
|
|
540
597
|
const staged = this.db.prepare(`SELECT import_run_id FROM import_runs
|
|
541
598
|
WHERE source_id=? AND parser_version=? AND status='staged'`).all(sourceId, parserVersion).map((row) => String(row.import_run_id));
|
|
542
599
|
const result = this.db.prepare(`UPDATE import_runs SET status='committed'
|
|
@@ -564,7 +621,7 @@ export class SessionRepository {
|
|
|
564
621
|
WHERE operation_id=?`).run(updated.observedAt, JSON.stringify(updated), operationId);
|
|
565
622
|
}
|
|
566
623
|
if (result.changes > 0)
|
|
567
|
-
this.
|
|
624
|
+
this.rebuildImportAnalytics(staged);
|
|
568
625
|
return result.changes;
|
|
569
626
|
});
|
|
570
627
|
return commit();
|
|
@@ -573,7 +630,7 @@ export class SessionRepository {
|
|
|
573
630
|
if (sourceIds.length === 0)
|
|
574
631
|
return 0;
|
|
575
632
|
const placeholders = sourceIds.map(() => '?').join(', ');
|
|
576
|
-
const commit = this.
|
|
633
|
+
const commit = this.maintainedAnalyticsTransaction(() => {
|
|
577
634
|
const params = [batchRunId, ...sourceIds];
|
|
578
635
|
const staged = this.db.prepare(`SELECT import_run_id FROM import_runs
|
|
579
636
|
WHERE batch_run_id=? AND source_id IN (${placeholders}) AND status='staged'`).all(...params).map((row) => String(row.import_run_id));
|
|
@@ -602,33 +659,84 @@ export class SessionRepository {
|
|
|
602
659
|
WHERE operation_id=?`).run(updated.observedAt, JSON.stringify(updated), operationId);
|
|
603
660
|
}
|
|
604
661
|
if (result.changes > 0)
|
|
605
|
-
this.
|
|
662
|
+
this.rebuildImportAnalytics(staged);
|
|
606
663
|
return result.changes;
|
|
607
664
|
});
|
|
608
665
|
return commit();
|
|
609
666
|
}
|
|
610
|
-
|
|
611
|
-
const
|
|
667
|
+
rebuildImportAnalytics(importRunIds) {
|
|
668
|
+
const affected = this.db.prepare(`SELECT DISTINCT s.workspace_id, s.session_id
|
|
612
669
|
FROM session_events e
|
|
613
|
-
JOIN
|
|
614
|
-
WHERE e.
|
|
615
|
-
const sessions =
|
|
670
|
+
JOIN sessions s ON s.session_id=e.session_id
|
|
671
|
+
WHERE e.import_run_id=?`);
|
|
672
|
+
const sessions = new Map();
|
|
673
|
+
for (const importRunId of importRunIds) {
|
|
674
|
+
for (const row of affected.all(importRunId)) {
|
|
675
|
+
sessions.set(String(row.session_id), String(row.workspace_id));
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
for (const [sessionId, workspaceId] of sessions) {
|
|
679
|
+
this.rebuildAnalytics(workspaceId, sessionId);
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
sourceImportTotals(sourceId, batchRunId) {
|
|
683
|
+
const totals = this.db.prepare(`SELECT COUNT(*) AS events, COUNT(DISTINCT e.session_id) AS sessions
|
|
616
684
|
FROM session_events e
|
|
617
685
|
JOIN import_runs r ON r.import_run_id=e.import_run_id
|
|
618
|
-
WHERE e.source_id=? AND r.batch_run_id=?`).get(sourceId, batchRunId)
|
|
619
|
-
return { sessions, events };
|
|
686
|
+
WHERE e.source_id=? AND r.batch_run_id=?`).get(sourceId, batchRunId);
|
|
687
|
+
return { sessions: Number(totals?.sessions ?? 0), events: Number(totals?.events ?? 0) };
|
|
620
688
|
}
|
|
621
689
|
getSession(id, workspaceId) {
|
|
622
690
|
const row = this.db.prepare(`SELECT s.data FROM sessions s
|
|
623
|
-
WHERE s.session_id=? AND
|
|
624
|
-
${workspaceId ? 'AND s.workspace_id=?' : ''}
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
691
|
+
WHERE s.session_id=? AND ${VISIBLE_SESSION_PREDICATE}
|
|
692
|
+
${workspaceId ? 'AND s.workspace_id=?' : ''}`)
|
|
693
|
+
.get(...(workspaceId ? [id, workspaceId] : [id]));
|
|
694
|
+
return row ? effectiveSessionLifecycle(JSON.parse(String(row.data))) : null;
|
|
695
|
+
}
|
|
696
|
+
findSessionsByReference(reference, workspaceId) {
|
|
697
|
+
const internal = this.getSession(reference, workspaceId);
|
|
698
|
+
if (internal)
|
|
699
|
+
return [internal];
|
|
700
|
+
const query = (predicate) => this.db.prepare(`SELECT s.data FROM sessions s
|
|
701
|
+
WHERE ${workspaceId ? 's.workspace_id=? AND' : ''} ${VISIBLE_SESSION_PREDICATE} AND (${predicate})
|
|
702
|
+
ORDER BY s.session_id`).all(...(workspaceId ? [workspaceId, reference] : [reference]))
|
|
703
|
+
.map((row) => effectiveSessionLifecycle(JSON.parse(String(row.data))));
|
|
704
|
+
const exact = query('s.native_session_id=?');
|
|
705
|
+
if (exact.length === 1)
|
|
706
|
+
return exact;
|
|
707
|
+
if (exact.length > 1) {
|
|
708
|
+
// Artifact IDs are redacted by native-extension sanitization. The
|
|
709
|
+
// adapter's boolean subagent flag survives. Only prefer a parent when
|
|
710
|
+
// every other match is a proven Claude subagent in the same workspace.
|
|
711
|
+
if (exact.every((session) => session.provider === 'claude'
|
|
712
|
+
&& session.workspaceId === exact[0].workspaceId)) {
|
|
713
|
+
const classified = exact.map((session) => {
|
|
714
|
+
const flags = this.db.prepare(`SELECT
|
|
715
|
+
MAX(json_extract(e.data, '$.extensions."native.claude".transcriptFamily.subagent')=0) AS parent,
|
|
716
|
+
MAX(json_extract(e.data, '$.extensions."native.claude".transcriptFamily.subagent')=1) AS subagent
|
|
717
|
+
FROM session_events e JOIN import_runs r ON r.import_run_id=e.import_run_id
|
|
718
|
+
WHERE e.session_id=? AND r.status='committed'`).get(session.sessionId);
|
|
719
|
+
return { session, parent: flags.parent === 1, subagent: flags.subagent === 1 };
|
|
720
|
+
});
|
|
721
|
+
const parents = classified.filter((item) => item.parent && !item.subagent);
|
|
722
|
+
if (parents.length === 1 && classified.every((item) => item === parents[0]
|
|
723
|
+
|| (item.subagent && !item.parent)))
|
|
724
|
+
return [parents[0].session];
|
|
725
|
+
}
|
|
726
|
+
return exact;
|
|
727
|
+
}
|
|
728
|
+
// substr treats %, _ and other characters literally rather than as LIKE patterns.
|
|
729
|
+
return this.db.prepare(`SELECT s.data FROM sessions s
|
|
730
|
+
WHERE ${workspaceId ? 's.workspace_id=? AND' : ''} ${VISIBLE_SESSION_PREDICATE}
|
|
731
|
+
AND (substr(s.native_session_id, 1, length(?))=?
|
|
732
|
+
OR substr(s.session_id, 1, length(?))=?)
|
|
733
|
+
ORDER BY s.session_id`).all(...(workspaceId ? [workspaceId, reference, reference, reference, reference]
|
|
734
|
+
: [reference, reference, reference, reference]))
|
|
735
|
+
.map((row) => effectiveSessionLifecycle(JSON.parse(String(row.data))));
|
|
736
|
+
}
|
|
737
|
+
listWorkspaceSessionCounts() {
|
|
738
|
+
return this.db.prepare(`SELECT s.workspace_id, COUNT(*) AS count FROM sessions s
|
|
739
|
+
WHERE ${VISIBLE_SESSION_PREDICATE} GROUP BY s.workspace_id ORDER BY s.workspace_id`).all().map((row) => ({ workspaceId: String(row.workspace_id), count: Number(row.count) }));
|
|
632
740
|
}
|
|
633
741
|
listSources() {
|
|
634
742
|
return this.db.prepare('SELECT data FROM session_sources ORDER BY provider, source_id').all().map((row) => JSON.parse(String(row.data)));
|
|
@@ -637,6 +745,7 @@ export class SessionRepository {
|
|
|
637
745
|
return this.db.prepare('SELECT DISTINCT workspace_id FROM sessions ORDER BY workspace_id').all().map((row) => String(row.workspace_id));
|
|
638
746
|
}
|
|
639
747
|
saveBatchImportRun(run) {
|
|
748
|
+
run = redactSessionValue(run).value;
|
|
640
749
|
const save = this.db.transaction(() => {
|
|
641
750
|
const prior = this.db.prepare('SELECT manifest_id, workspace_id FROM batch_import_runs WHERE batch_run_id=?').get(run.runId);
|
|
642
751
|
if (prior && (String(prior.manifest_id) !== run.manifestId
|
|
@@ -655,6 +764,22 @@ export class SessionRepository {
|
|
|
655
764
|
const row = this.db.prepare('SELECT data FROM batch_import_runs WHERE batch_run_id=?').get(runId);
|
|
656
765
|
return row ? JSON.parse(String(row.data)) : null;
|
|
657
766
|
}
|
|
767
|
+
/** Call only while holding the catalog import lease, before starting a new import. */
|
|
768
|
+
interruptRunningBatchImports(now = new Date()) {
|
|
769
|
+
const interruptedAt = now.toISOString();
|
|
770
|
+
return this.db.transaction(() => {
|
|
771
|
+
const rows = this.db.prepare("SELECT data FROM batch_import_runs WHERE status='running'").all();
|
|
772
|
+
return rows.map((row) => {
|
|
773
|
+
const run = JSON.parse(String(row.data));
|
|
774
|
+
run.status = 'interrupted';
|
|
775
|
+
run.interruptedAt = interruptedAt;
|
|
776
|
+
run.updatedAt = interruptedAt;
|
|
777
|
+
run.completedAt = null;
|
|
778
|
+
this.saveBatchImportRun(run);
|
|
779
|
+
return { runId: run.runId, interruptedAt };
|
|
780
|
+
});
|
|
781
|
+
})();
|
|
782
|
+
}
|
|
658
783
|
getBatchImportRunForManifest(manifestId, workspaceId) {
|
|
659
784
|
const row = this.db.prepare(`SELECT data FROM batch_import_runs
|
|
660
785
|
WHERE manifest_id=? AND workspace_id=?`).get(manifestId, workspaceId);
|
|
@@ -670,11 +795,7 @@ export class SessionRepository {
|
|
|
670
795
|
: coverage;
|
|
671
796
|
}
|
|
672
797
|
listSessions(options) {
|
|
673
|
-
const where = [
|
|
674
|
-
SELECT 1 FROM session_events e
|
|
675
|
-
JOIN import_runs r ON r.import_run_id=e.import_run_id
|
|
676
|
-
WHERE e.session_id=s.session_id AND r.status='committed'
|
|
677
|
-
)`];
|
|
798
|
+
const where = [VISIBLE_SESSION_PREDICATE];
|
|
678
799
|
const scopeDigest = sessionListScopeDigest(options);
|
|
679
800
|
const cursor = decodeSessionListCursor(options.cursor);
|
|
680
801
|
if (cursor && cursor.scopeDigest !== scopeDigest) {
|
|
@@ -702,18 +823,18 @@ export class SessionRepository {
|
|
|
702
823
|
const pageParams = [...params];
|
|
703
824
|
if (cursor) {
|
|
704
825
|
pageWhere.push(`(
|
|
705
|
-
COALESCE(json_extract(s.data, '$.updatedAt'), '')
|
|
826
|
+
COALESCE(json_extract(s.data, '$.updatedAt'), '') < ?
|
|
706
827
|
OR (
|
|
707
828
|
COALESCE(json_extract(s.data, '$.updatedAt'), '') = ?
|
|
708
|
-
AND s.session_id
|
|
829
|
+
AND s.session_id < ?
|
|
709
830
|
)
|
|
710
831
|
)`);
|
|
711
832
|
pageParams.push(cursor.updatedAt, cursor.updatedAt, cursor.sessionId);
|
|
712
833
|
}
|
|
713
834
|
const items = this.db.prepare(`SELECT s.data FROM sessions s WHERE ${pageWhere.join(' AND ')}
|
|
714
|
-
ORDER BY COALESCE(json_extract(s.data, '$.updatedAt'), ''), s.session_id
|
|
835
|
+
ORDER BY COALESCE(json_extract(s.data, '$.updatedAt'), '') DESC, s.session_id DESC
|
|
715
836
|
LIMIT ?${options.offset ? ' OFFSET ?' : ''}`).all(...pageParams, options.limit + 1, ...(options.offset ? [options.offset] : []))
|
|
716
|
-
.map((row) => JSON.parse(String(row.data)));
|
|
837
|
+
.map((row) => effectiveSessionLifecycle(JSON.parse(String(row.data))));
|
|
717
838
|
const page = items.slice(0, options.limit);
|
|
718
839
|
const last = page.at(-1);
|
|
719
840
|
return {
|
|
@@ -738,6 +859,7 @@ export class SessionRepository {
|
|
|
738
859
|
.map((row) => String(row.tag));
|
|
739
860
|
}
|
|
740
861
|
tagSession(sessionId, tag, workspaceId) {
|
|
862
|
+
tag = redactSessionText(tag).text;
|
|
741
863
|
const mutate = this.db.transaction(() => {
|
|
742
864
|
if (!this.getSession(sessionId, workspaceId))
|
|
743
865
|
return false;
|
|
@@ -778,7 +900,7 @@ export class SessionRepository {
|
|
|
778
900
|
e.session_id,
|
|
779
901
|
e.sequence_no,
|
|
780
902
|
e.event_id`).all(workspaceId).map((row) => ({
|
|
781
|
-
session: JSON.parse(String(row.session_data)),
|
|
903
|
+
session: effectiveSessionLifecycle(JSON.parse(String(row.session_data))),
|
|
782
904
|
event: JSON.parse(String(row.event_data)),
|
|
783
905
|
}));
|
|
784
906
|
}
|
|
@@ -919,6 +1041,14 @@ export class SessionRepository {
|
|
|
919
1041
|
};
|
|
920
1042
|
}
|
|
921
1043
|
rebuildAnalytics(workspaceId, sessionId) {
|
|
1044
|
+
return this.maintainedAnalyticsTransaction(() => {
|
|
1045
|
+
const inserted = this.rebuildAnalyticsFacts(workspaceId, sessionId);
|
|
1046
|
+
if (!workspaceId && !sessionId)
|
|
1047
|
+
this.markAnalyticsVerified();
|
|
1048
|
+
return inserted;
|
|
1049
|
+
})();
|
|
1050
|
+
}
|
|
1051
|
+
rebuildAnalyticsFacts(workspaceId, sessionId) {
|
|
922
1052
|
const where = [
|
|
923
1053
|
`r.status='committed'`,
|
|
924
1054
|
`s.lifecycle!='tombstoned'`,
|
|
@@ -1087,7 +1217,10 @@ export class SessionRepository {
|
|
|
1087
1217
|
}
|
|
1088
1218
|
}
|
|
1089
1219
|
const saved = candidates.map((input) => {
|
|
1090
|
-
const
|
|
1220
|
+
const redacted = redactSessionValue(input);
|
|
1221
|
+
const parsed = IntelligenceCandidateSchema.parse(redacted.value);
|
|
1222
|
+
if (redacted.classes.length)
|
|
1223
|
+
parsed.sensitivity = 'sensitive';
|
|
1091
1224
|
this.assertCandidateEvidence(parsed);
|
|
1092
1225
|
const priorRow = this.db.prepare(`SELECT data FROM intelligence_candidates
|
|
1093
1226
|
WHERE candidate_id=? ORDER BY version DESC LIMIT 1`).get(parsed.candidateId);
|
|
@@ -1155,6 +1288,7 @@ export class SessionRepository {
|
|
|
1155
1288
|
return rows.map((row) => IntelligenceCandidateSchema.parse(JSON.parse(String(row.data))));
|
|
1156
1289
|
}
|
|
1157
1290
|
reviewCandidate(input) {
|
|
1291
|
+
input = redactSessionValue(input).value;
|
|
1158
1292
|
const review = this.db.transaction(() => {
|
|
1159
1293
|
const candidate = this.getCandidate(input.candidateId, input.version, input.workspaceId);
|
|
1160
1294
|
if (!candidate) {
|
|
@@ -1216,7 +1350,7 @@ export class SessionRepository {
|
|
|
1216
1350
|
}
|
|
1217
1351
|
recordPromotion(receiptInput) {
|
|
1218
1352
|
const record = this.db.transaction(() => {
|
|
1219
|
-
const receipt = PromotionReceiptSchema.parse(receiptInput);
|
|
1353
|
+
const receipt = PromotionReceiptSchema.parse(redactSessionValue(receiptInput).value);
|
|
1220
1354
|
const existing = this.getPromotionReceipt(receipt.candidateId, receipt.candidateVersion, receipt.consumer);
|
|
1221
1355
|
if (existing)
|
|
1222
1356
|
return { ...existing, duplicate: true };
|
|
@@ -1283,6 +1417,7 @@ export class SessionRepository {
|
|
|
1283
1417
|
return row ? JSON.parse(String(row.checkpoint)) : null;
|
|
1284
1418
|
}
|
|
1285
1419
|
relocateSource(sourceId, redactedLocator, workspaceId) {
|
|
1420
|
+
redactedLocator = redactSessionText(redactedLocator).text;
|
|
1286
1421
|
const relocate = this.db.transaction(() => {
|
|
1287
1422
|
const row = this.db.prepare(`SELECT src.data FROM session_sources src
|
|
1288
1423
|
WHERE src.source_id=? ${workspaceId ? `AND EXISTS (
|
|
@@ -1340,7 +1475,7 @@ export class SessionRepository {
|
|
|
1340
1475
|
};
|
|
1341
1476
|
}
|
|
1342
1477
|
tombstoneSession(sessionId, workspaceId) {
|
|
1343
|
-
const tombstone = this.
|
|
1478
|
+
const tombstone = this.maintainedAnalyticsTransaction(() => {
|
|
1344
1479
|
const row = this.db.prepare(`SELECT data, workspace_id FROM sessions
|
|
1345
1480
|
WHERE session_id=? ${workspaceId ? 'AND workspace_id=?' : ''}`).get(...(workspaceId ? [sessionId, workspaceId] : [sessionId]));
|
|
1346
1481
|
if (!row)
|
|
@@ -1369,7 +1504,7 @@ export class SessionRepository {
|
|
|
1369
1504
|
return tombstone();
|
|
1370
1505
|
}
|
|
1371
1506
|
restoreSession(sessionId, workspaceId) {
|
|
1372
|
-
const restore = this.
|
|
1507
|
+
const restore = this.maintainedAnalyticsTransaction(() => {
|
|
1373
1508
|
const row = this.db.prepare(`SELECT data, workspace_id FROM sessions
|
|
1374
1509
|
WHERE session_id=? ${workspaceId ? 'AND workspace_id=?' : ''}`).get(...(workspaceId ? [sessionId, workspaceId] : [sessionId]));
|
|
1375
1510
|
if (!row)
|
|
@@ -1483,6 +1618,7 @@ export class SessionRepository {
|
|
|
1483
1618
|
return rows.map((row) => JSON.parse(String(row.data)));
|
|
1484
1619
|
}
|
|
1485
1620
|
purgeSession(input) {
|
|
1621
|
+
input = redactSessionValue(input).value;
|
|
1486
1622
|
const existing = this.db.prepare('SELECT data FROM deletion_receipts WHERE operation_id=?').get(input.preview.operationId);
|
|
1487
1623
|
if (existing)
|
|
1488
1624
|
return JSON.parse(String(existing.data));
|
|
@@ -1502,7 +1638,7 @@ export class SessionRepository {
|
|
|
1502
1638
|
if (!mutationWorkspaceId) {
|
|
1503
1639
|
throw new SessionContractError('OPERATION_NOT_AUTHORIZED', 'purge mutation lacks an authorized workspace');
|
|
1504
1640
|
}
|
|
1505
|
-
const apply = this.
|
|
1641
|
+
const apply = this.maintainedAnalyticsTransaction(() => {
|
|
1506
1642
|
for (const decision of validatedDecisions) {
|
|
1507
1643
|
this.db.prepare(`INSERT INTO promotion_dependency_decisions
|
|
1508
1644
|
(operation_id, dependent_id, action, basis) VALUES (?, ?, ?, ?)`).run(input.preview.operationId, decision.dependentId, decision.action, decision.basis);
|
|
@@ -1596,7 +1732,7 @@ export class SessionRepository {
|
|
|
1596
1732
|
return apply();
|
|
1597
1733
|
}
|
|
1598
1734
|
reindex(workspaceId) {
|
|
1599
|
-
const rebuild = this.
|
|
1735
|
+
const rebuild = this.maintainedAnalyticsTransaction(() => {
|
|
1600
1736
|
let indexed = 0;
|
|
1601
1737
|
if (!workspaceId) {
|
|
1602
1738
|
this.db.exec('REINDEX');
|