@aiwg/cli 2026.10.3 → 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/model-capabilities.v1.json +96 -4
- package/bin/aiwg.mjs +50 -27
- 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 +2 -0
- 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/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 +19 -2
- package/dist/src/cli/command-log.js +2 -3
- 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 +19 -12
- package/dist/src/cli/handlers/diagnose.js +4 -3
- package/dist/src/cli/handlers/effect.js +4 -2
- package/dist/src/cli/handlers/evidence.js +3 -0
- 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 +4 -1
- package/dist/src/cli/handlers/lint.js +5 -0
- package/dist/src/cli/handlers/models.js +104 -8
- package/dist/src/cli/handlers/ralph-launcher.js +2 -0
- package/dist/src/cli/handlers/refresh.js +12 -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 +1 -2
- package/dist/src/cli/handlers/script-runner.js +3 -2
- package/dist/src/cli/handlers/session.js +19 -9
- package/dist/src/cli/handlers/sessions.js +98 -37
- package/dist/src/cli/handlers/setup-manifest.js +39 -44
- package/dist/src/cli/handlers/setup.js +41 -0
- package/dist/src/cli/handlers/steward.js +11 -0
- package/dist/src/cli/handlers/subcommands.js +57 -2
- package/dist/src/cli/handlers/uhp.js +3 -0
- package/dist/src/cli/handlers/use.js +294 -55
- package/dist/src/cli/handlers/utilities.js +26 -10
- package/dist/src/cli/handlers/version.js +8 -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 +87 -37
- package/dist/src/config/cli.js +111 -5
- package/dist/src/config/decision-config.js +106 -0
- package/dist/src/config/dispatch-thresholds-runtime.d.mts +8 -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-runtime.d.mts +16 -0
- package/dist/src/config/user-config-dir.d.mts +9 -0
- package/dist/src/config/user-config.js +2 -1
- package/dist/src/config/user-registry.js +23 -15
- package/dist/src/config/user-state.js +7 -0
- package/dist/src/decision/ask.js +203 -43
- package/dist/src/decision/context-live-qualification.js +2 -2
- package/dist/src/decision/driver.js +13 -8
- 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 +2 -15
- 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 +5 -13
- package/dist/src/decision/heldout/contract.js +30 -7
- package/dist/src/decision/jev-credentials.js +15 -1
- package/dist/src/decision/ledger.js +131 -28
- 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/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/gates/providers/loader.js +61 -17
- package/dist/src/installation/manager-command.d.mts +18 -0
- package/dist/src/installation/manager-command.mjs +14 -2
- package/dist/src/installation/manager.d.mts +49 -0
- package/dist/src/installation/manager.mjs +78 -3
- 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 +7 -1
- 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 +36 -11
- package/dist/src/mcp/config-file.d.mts +28 -0
- package/dist/src/mcp/config-layers.d.mts +36 -0
- package/dist/src/mcp/credentials.d.mts +51 -0
- package/dist/src/mcp/grok-build-config.d.mts +6 -0
- package/dist/src/mcp/grok-build-config.mjs +1 -1
- package/dist/src/mcp/helpers.mjs +3 -2
- 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/registry.js +3 -93
- package/dist/src/mcp/registry.mjs +3 -87
- 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 +37 -375
- 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-strip-mcp.d.mts +1 -0
- package/dist/src/mcp/tool-filters.d.mts +46 -0
- package/dist/src/mcp/tools/decision.mjs +12 -11
- package/dist/src/mcp/tools/discovery.mjs +62 -55
- package/dist/src/mcp/tools/orchestration.mjs +12 -2
- package/dist/src/mcp/tools/worker-invoke.mjs +1340 -23
- package/dist/src/mcp/tools/worker-shell-control.mjs +52 -21
- package/dist/src/mcp/tools/worker-stdin-runtime.mjs +3 -3
- package/dist/src/mission-protocol/codecs.js +8 -0
- package/dist/src/models/config-loader.js +7 -2
- package/dist/src/models/model-capabilities.v1.json +96 -4
- package/dist/src/models/model-discovery.js +76 -11
- package/dist/src/models/provider-policy.js +101 -7
- package/dist/src/models/qualification-digest.d.mts +2 -0
- package/dist/src/models/resolver.js +12 -10
- package/dist/src/models/worker-direct-readiness.js +65 -44
- package/dist/src/models/worker-dispatch-offer.js +3 -3
- package/dist/src/models/worker-health-readiness.js +16 -3
- package/dist/src/models/worker-installation.d.mts +39 -0
- package/dist/src/models/worker-installation.mjs +135 -28
- package/dist/src/process/bounded-child-process.d.mts +84 -0
- package/dist/src/process/bounded-child-process.mjs +43 -0
- package/dist/src/process/cli-command.d.mts +16 -0
- package/dist/src/process/signal-child.d.mts +6 -0
- package/dist/src/process/signal-child.mjs +7 -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 +12 -4
- 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/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/mission-conductor.js +38 -12
- package/dist/src/serve/worker-invocation.js +30 -10
- package/dist/src/serve/worker-stdin-frame.d.mts +10 -0
- package/dist/src/sessions/adapter-registry.js +23 -19
- 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 +10 -10
- package/dist/src/sessions/adapters/grok-build.js +11 -11
- package/dist/src/sessions/adapters/grokbot.js +24 -13
- package/dist/src/sessions/adapters/hermes.js +27 -29
- package/dist/src/sessions/adapters/muse-workspace-scan.js +31 -11
- package/dist/src/sessions/adapters/muse.js +150 -93
- 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 +29 -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 +16 -8
- package/dist/src/sessions/batch-import.js +51 -11
- package/dist/src/sessions/contracts.js +40 -2
- package/dist/src/sessions/coverage-preflight.js +1 -1
- package/dist/src/sessions/export-plan.js +4 -3
- 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 +60 -38
- 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 +147 -52
- package/dist/src/sessions/workspace-discovery.js +221 -56
- package/dist/src/sessions/workspace-matching.js +107 -0
- 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 +7 -15
- 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 +76 -18
- package/dist/src/storage/backends/fs.js +18 -76
- package/dist/src/storage/backends/obsidian.js +1 -0
- package/dist/src/tracker/forge-http.js +2 -1
- package/dist/src/update/checker.d.mts +2 -0
- 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/package.json +15 -2
- package/schemas/models/model-catalog.v1.schema.json +1 -1
- package/schemas/models/provider-model-capabilities.v1.schema.json +6 -0
- package/tools/_resolve-impl.mjs +13 -15
- package/tools/agents/deploy-agents.mjs +49 -21
- package/tools/agents/providers/base.mjs +104 -134
- 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/hermes.mjs +57 -47
- 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 +6 -4
- package/tools/providers/omp-transport.mjs +4 -2
- package/tools/ralph-external/lib/consecutive-failure-circuit-breaker.mjs +1748 -0
- package/tools/ralph-external/lib/launcher-recovery-evidence.mjs +55 -0
- package/tools/ralph-external/lib/omp-adapter.mjs +1 -1
- package/tools/ralph-external/lib/pi-adapter.mjs +0 -4
- package/tools/ralph-external/lib/provider-adapter.mjs +59 -1
- 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 +1 -1
- 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 +1194 -231
|
@@ -1,7 +1,8 @@
|
|
|
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';
|
|
@@ -124,6 +125,12 @@ export class SessionRepository {
|
|
|
124
125
|
ON sessions(workspace_id, source_id, lifecycle);
|
|
125
126
|
CREATE INDEX IF NOT EXISTS idx_event_session_sequence
|
|
126
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);
|
|
127
134
|
CREATE INDEX IF NOT EXISTS idx_session_analytics_scope
|
|
128
135
|
ON session_analytics_facts(
|
|
129
136
|
workspace_id, category, provider, status, occurred_at, fact_id
|
|
@@ -131,6 +138,9 @@ export class SessionRepository {
|
|
|
131
138
|
CREATE VIRTUAL TABLE IF NOT EXISTS session_event_fts USING fts5(
|
|
132
139
|
event_id UNINDEXED, searchable_text, tokenize='unicode61'
|
|
133
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);
|
|
134
144
|
`);
|
|
135
145
|
const deletionReceiptColumns = this.db.prepare('PRAGMA table_info(deletion_receipts)').all().map((row) => String(row.name));
|
|
136
146
|
if (!deletionReceiptColumns.includes('workspace_id')) {
|
|
@@ -154,48 +164,79 @@ export class SessionRepository {
|
|
|
154
164
|
CREATE INDEX IF NOT EXISTS idx_mutation_audit_workspace
|
|
155
165
|
ON mutation_audit(workspace_id, occurred_at, operation_id)
|
|
156
166
|
;
|
|
167
|
+
CREATE INDEX IF NOT EXISTS idx_import_runs_batch
|
|
168
|
+
ON import_runs(batch_run_id);
|
|
157
169
|
CREATE INDEX IF NOT EXISTS idx_batch_import_workspace
|
|
158
170
|
ON batch_import_runs(workspace_id, updated_at, batch_run_id)
|
|
159
171
|
`);
|
|
172
|
+
this.initializeAnalyticsVerification();
|
|
160
173
|
this.alignSessionFtsRowids();
|
|
161
174
|
this.migrateSessionPolicyAndProviderIdentity();
|
|
162
175
|
this.migrateEventOriginAndIntent();
|
|
163
176
|
this.alignSessionAnalytics();
|
|
164
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
|
+
}
|
|
165
215
|
alignSessionAnalytics() {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
const factSessions = Number(this.db.prepare('SELECT COUNT(DISTINCT session_id) AS count FROM session_analytics_facts').get()?.count ?? 0);
|
|
172
|
-
const sourceSessions = Number(this.db.prepare(`SELECT COUNT(DISTINCT e.session_id) AS count
|
|
173
|
-
FROM session_events e
|
|
174
|
-
JOIN import_runs r ON r.import_run_id=e.import_run_id
|
|
175
|
-
JOIN sessions s ON s.session_id=e.session_id
|
|
176
|
-
WHERE r.status='committed' AND s.lifecycle!='tombstoned'`).get()?.count ?? 0);
|
|
177
|
-
if (eventCount === 0 || factSessions === sourceSessions)
|
|
178
|
-
return;
|
|
179
|
-
this.rebuildAnalytics();
|
|
216
|
+
this.db.transaction(() => {
|
|
217
|
+
if (this.analyticsVerified())
|
|
218
|
+
return;
|
|
219
|
+
this.rebuildAnalytics();
|
|
220
|
+
})();
|
|
180
221
|
}
|
|
181
222
|
alignSessionFtsRowids() {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
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;
|
|
191
233
|
this.db.exec('DELETE FROM session_event_fts');
|
|
192
234
|
this.db.exec(`
|
|
193
235
|
INSERT INTO session_event_fts(rowid, event_id, searchable_text)
|
|
194
236
|
SELECT rowid, event_id, json_extract(data, '$.searchableText')
|
|
195
237
|
FROM session_events
|
|
196
238
|
`);
|
|
197
|
-
});
|
|
198
|
-
rebuild();
|
|
239
|
+
})();
|
|
199
240
|
}
|
|
200
241
|
migrateSessionPolicyAndProviderIdentity() {
|
|
201
242
|
this.runCatalogMigration(POLICY_PROVIDER_MIGRATION, () => {
|
|
@@ -331,6 +372,7 @@ export class SessionRepository {
|
|
|
331
372
|
transaction();
|
|
332
373
|
}
|
|
333
374
|
emitMutation(input) {
|
|
375
|
+
input = redactSessionValue(input).value;
|
|
334
376
|
const unsigned = {
|
|
335
377
|
contractVersion: '1.0.0',
|
|
336
378
|
...input,
|
|
@@ -435,7 +477,17 @@ export class SessionRepository {
|
|
|
435
477
|
};
|
|
436
478
|
}
|
|
437
479
|
applyImport(batch, checkpoint, publish = true) {
|
|
438
|
-
|
|
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(() => {
|
|
439
491
|
const existing = this.db.prepare('SELECT outcome, counts, checkpoint FROM import_receipts WHERE import_run_id = ?').get(batch.run.importRunId);
|
|
440
492
|
if (existing) {
|
|
441
493
|
const counts = JSON.parse(String(existing.counts));
|
|
@@ -541,7 +593,7 @@ export class SessionRepository {
|
|
|
541
593
|
return apply();
|
|
542
594
|
}
|
|
543
595
|
commitStagedImports(sourceId, parserVersion) {
|
|
544
|
-
const commit = this.
|
|
596
|
+
const commit = this.maintainedAnalyticsTransaction(() => {
|
|
545
597
|
const staged = this.db.prepare(`SELECT import_run_id FROM import_runs
|
|
546
598
|
WHERE source_id=? AND parser_version=? AND status='staged'`).all(sourceId, parserVersion).map((row) => String(row.import_run_id));
|
|
547
599
|
const result = this.db.prepare(`UPDATE import_runs SET status='committed'
|
|
@@ -569,7 +621,7 @@ export class SessionRepository {
|
|
|
569
621
|
WHERE operation_id=?`).run(updated.observedAt, JSON.stringify(updated), operationId);
|
|
570
622
|
}
|
|
571
623
|
if (result.changes > 0)
|
|
572
|
-
this.
|
|
624
|
+
this.rebuildImportAnalytics(staged);
|
|
573
625
|
return result.changes;
|
|
574
626
|
});
|
|
575
627
|
return commit();
|
|
@@ -578,7 +630,7 @@ export class SessionRepository {
|
|
|
578
630
|
if (sourceIds.length === 0)
|
|
579
631
|
return 0;
|
|
580
632
|
const placeholders = sourceIds.map(() => '?').join(', ');
|
|
581
|
-
const commit = this.
|
|
633
|
+
const commit = this.maintainedAnalyticsTransaction(() => {
|
|
582
634
|
const params = [batchRunId, ...sourceIds];
|
|
583
635
|
const staged = this.db.prepare(`SELECT import_run_id FROM import_runs
|
|
584
636
|
WHERE batch_run_id=? AND source_id IN (${placeholders}) AND status='staged'`).all(...params).map((row) => String(row.import_run_id));
|
|
@@ -607,28 +659,39 @@ export class SessionRepository {
|
|
|
607
659
|
WHERE operation_id=?`).run(updated.observedAt, JSON.stringify(updated), operationId);
|
|
608
660
|
}
|
|
609
661
|
if (result.changes > 0)
|
|
610
|
-
this.
|
|
662
|
+
this.rebuildImportAnalytics(staged);
|
|
611
663
|
return result.changes;
|
|
612
664
|
});
|
|
613
665
|
return commit();
|
|
614
666
|
}
|
|
615
|
-
|
|
616
|
-
const
|
|
667
|
+
rebuildImportAnalytics(importRunIds) {
|
|
668
|
+
const affected = this.db.prepare(`SELECT DISTINCT s.workspace_id, s.session_id
|
|
617
669
|
FROM session_events e
|
|
618
|
-
JOIN
|
|
619
|
-
WHERE e.
|
|
620
|
-
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
|
|
621
684
|
FROM session_events e
|
|
622
685
|
JOIN import_runs r ON r.import_run_id=e.import_run_id
|
|
623
|
-
WHERE e.source_id=? AND r.batch_run_id=?`).get(sourceId, batchRunId)
|
|
624
|
-
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) };
|
|
625
688
|
}
|
|
626
689
|
getSession(id, workspaceId) {
|
|
627
690
|
const row = this.db.prepare(`SELECT s.data FROM sessions s
|
|
628
691
|
WHERE s.session_id=? AND ${VISIBLE_SESSION_PREDICATE}
|
|
629
692
|
${workspaceId ? 'AND s.workspace_id=?' : ''}`)
|
|
630
693
|
.get(...(workspaceId ? [id, workspaceId] : [id]));
|
|
631
|
-
return row ? JSON.parse(String(row.data)) : null;
|
|
694
|
+
return row ? effectiveSessionLifecycle(JSON.parse(String(row.data))) : null;
|
|
632
695
|
}
|
|
633
696
|
findSessionsByReference(reference, workspaceId) {
|
|
634
697
|
const internal = this.getSession(reference, workspaceId);
|
|
@@ -637,7 +700,7 @@ export class SessionRepository {
|
|
|
637
700
|
const query = (predicate) => this.db.prepare(`SELECT s.data FROM sessions s
|
|
638
701
|
WHERE ${workspaceId ? 's.workspace_id=? AND' : ''} ${VISIBLE_SESSION_PREDICATE} AND (${predicate})
|
|
639
702
|
ORDER BY s.session_id`).all(...(workspaceId ? [workspaceId, reference] : [reference]))
|
|
640
|
-
.map((row) => JSON.parse(String(row.data)));
|
|
703
|
+
.map((row) => effectiveSessionLifecycle(JSON.parse(String(row.data))));
|
|
641
704
|
const exact = query('s.native_session_id=?');
|
|
642
705
|
if (exact.length === 1)
|
|
643
706
|
return exact;
|
|
@@ -669,7 +732,7 @@ export class SessionRepository {
|
|
|
669
732
|
OR substr(s.session_id, 1, length(?))=?)
|
|
670
733
|
ORDER BY s.session_id`).all(...(workspaceId ? [workspaceId, reference, reference, reference, reference]
|
|
671
734
|
: [reference, reference, reference, reference]))
|
|
672
|
-
.map((row) => JSON.parse(String(row.data)));
|
|
735
|
+
.map((row) => effectiveSessionLifecycle(JSON.parse(String(row.data))));
|
|
673
736
|
}
|
|
674
737
|
listWorkspaceSessionCounts() {
|
|
675
738
|
return this.db.prepare(`SELECT s.workspace_id, COUNT(*) AS count FROM sessions s
|
|
@@ -682,6 +745,7 @@ export class SessionRepository {
|
|
|
682
745
|
return this.db.prepare('SELECT DISTINCT workspace_id FROM sessions ORDER BY workspace_id').all().map((row) => String(row.workspace_id));
|
|
683
746
|
}
|
|
684
747
|
saveBatchImportRun(run) {
|
|
748
|
+
run = redactSessionValue(run).value;
|
|
685
749
|
const save = this.db.transaction(() => {
|
|
686
750
|
const prior = this.db.prepare('SELECT manifest_id, workspace_id FROM batch_import_runs WHERE batch_run_id=?').get(run.runId);
|
|
687
751
|
if (prior && (String(prior.manifest_id) !== run.manifestId
|
|
@@ -700,6 +764,22 @@ export class SessionRepository {
|
|
|
700
764
|
const row = this.db.prepare('SELECT data FROM batch_import_runs WHERE batch_run_id=?').get(runId);
|
|
701
765
|
return row ? JSON.parse(String(row.data)) : null;
|
|
702
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
|
+
}
|
|
703
783
|
getBatchImportRunForManifest(manifestId, workspaceId) {
|
|
704
784
|
const row = this.db.prepare(`SELECT data FROM batch_import_runs
|
|
705
785
|
WHERE manifest_id=? AND workspace_id=?`).get(manifestId, workspaceId);
|
|
@@ -743,18 +823,18 @@ export class SessionRepository {
|
|
|
743
823
|
const pageParams = [...params];
|
|
744
824
|
if (cursor) {
|
|
745
825
|
pageWhere.push(`(
|
|
746
|
-
COALESCE(json_extract(s.data, '$.updatedAt'), '')
|
|
826
|
+
COALESCE(json_extract(s.data, '$.updatedAt'), '') < ?
|
|
747
827
|
OR (
|
|
748
828
|
COALESCE(json_extract(s.data, '$.updatedAt'), '') = ?
|
|
749
|
-
AND s.session_id
|
|
829
|
+
AND s.session_id < ?
|
|
750
830
|
)
|
|
751
831
|
)`);
|
|
752
832
|
pageParams.push(cursor.updatedAt, cursor.updatedAt, cursor.sessionId);
|
|
753
833
|
}
|
|
754
834
|
const items = this.db.prepare(`SELECT s.data FROM sessions s WHERE ${pageWhere.join(' AND ')}
|
|
755
|
-
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
|
|
756
836
|
LIMIT ?${options.offset ? ' OFFSET ?' : ''}`).all(...pageParams, options.limit + 1, ...(options.offset ? [options.offset] : []))
|
|
757
|
-
.map((row) => JSON.parse(String(row.data)));
|
|
837
|
+
.map((row) => effectiveSessionLifecycle(JSON.parse(String(row.data))));
|
|
758
838
|
const page = items.slice(0, options.limit);
|
|
759
839
|
const last = page.at(-1);
|
|
760
840
|
return {
|
|
@@ -779,6 +859,7 @@ export class SessionRepository {
|
|
|
779
859
|
.map((row) => String(row.tag));
|
|
780
860
|
}
|
|
781
861
|
tagSession(sessionId, tag, workspaceId) {
|
|
862
|
+
tag = redactSessionText(tag).text;
|
|
782
863
|
const mutate = this.db.transaction(() => {
|
|
783
864
|
if (!this.getSession(sessionId, workspaceId))
|
|
784
865
|
return false;
|
|
@@ -819,7 +900,7 @@ export class SessionRepository {
|
|
|
819
900
|
e.session_id,
|
|
820
901
|
e.sequence_no,
|
|
821
902
|
e.event_id`).all(workspaceId).map((row) => ({
|
|
822
|
-
session: JSON.parse(String(row.session_data)),
|
|
903
|
+
session: effectiveSessionLifecycle(JSON.parse(String(row.session_data))),
|
|
823
904
|
event: JSON.parse(String(row.event_data)),
|
|
824
905
|
}));
|
|
825
906
|
}
|
|
@@ -960,6 +1041,14 @@ export class SessionRepository {
|
|
|
960
1041
|
};
|
|
961
1042
|
}
|
|
962
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) {
|
|
963
1052
|
const where = [
|
|
964
1053
|
`r.status='committed'`,
|
|
965
1054
|
`s.lifecycle!='tombstoned'`,
|
|
@@ -1128,7 +1217,10 @@ export class SessionRepository {
|
|
|
1128
1217
|
}
|
|
1129
1218
|
}
|
|
1130
1219
|
const saved = candidates.map((input) => {
|
|
1131
|
-
const
|
|
1220
|
+
const redacted = redactSessionValue(input);
|
|
1221
|
+
const parsed = IntelligenceCandidateSchema.parse(redacted.value);
|
|
1222
|
+
if (redacted.classes.length)
|
|
1223
|
+
parsed.sensitivity = 'sensitive';
|
|
1132
1224
|
this.assertCandidateEvidence(parsed);
|
|
1133
1225
|
const priorRow = this.db.prepare(`SELECT data FROM intelligence_candidates
|
|
1134
1226
|
WHERE candidate_id=? ORDER BY version DESC LIMIT 1`).get(parsed.candidateId);
|
|
@@ -1196,6 +1288,7 @@ export class SessionRepository {
|
|
|
1196
1288
|
return rows.map((row) => IntelligenceCandidateSchema.parse(JSON.parse(String(row.data))));
|
|
1197
1289
|
}
|
|
1198
1290
|
reviewCandidate(input) {
|
|
1291
|
+
input = redactSessionValue(input).value;
|
|
1199
1292
|
const review = this.db.transaction(() => {
|
|
1200
1293
|
const candidate = this.getCandidate(input.candidateId, input.version, input.workspaceId);
|
|
1201
1294
|
if (!candidate) {
|
|
@@ -1257,7 +1350,7 @@ export class SessionRepository {
|
|
|
1257
1350
|
}
|
|
1258
1351
|
recordPromotion(receiptInput) {
|
|
1259
1352
|
const record = this.db.transaction(() => {
|
|
1260
|
-
const receipt = PromotionReceiptSchema.parse(receiptInput);
|
|
1353
|
+
const receipt = PromotionReceiptSchema.parse(redactSessionValue(receiptInput).value);
|
|
1261
1354
|
const existing = this.getPromotionReceipt(receipt.candidateId, receipt.candidateVersion, receipt.consumer);
|
|
1262
1355
|
if (existing)
|
|
1263
1356
|
return { ...existing, duplicate: true };
|
|
@@ -1324,6 +1417,7 @@ export class SessionRepository {
|
|
|
1324
1417
|
return row ? JSON.parse(String(row.checkpoint)) : null;
|
|
1325
1418
|
}
|
|
1326
1419
|
relocateSource(sourceId, redactedLocator, workspaceId) {
|
|
1420
|
+
redactedLocator = redactSessionText(redactedLocator).text;
|
|
1327
1421
|
const relocate = this.db.transaction(() => {
|
|
1328
1422
|
const row = this.db.prepare(`SELECT src.data FROM session_sources src
|
|
1329
1423
|
WHERE src.source_id=? ${workspaceId ? `AND EXISTS (
|
|
@@ -1381,7 +1475,7 @@ export class SessionRepository {
|
|
|
1381
1475
|
};
|
|
1382
1476
|
}
|
|
1383
1477
|
tombstoneSession(sessionId, workspaceId) {
|
|
1384
|
-
const tombstone = this.
|
|
1478
|
+
const tombstone = this.maintainedAnalyticsTransaction(() => {
|
|
1385
1479
|
const row = this.db.prepare(`SELECT data, workspace_id FROM sessions
|
|
1386
1480
|
WHERE session_id=? ${workspaceId ? 'AND workspace_id=?' : ''}`).get(...(workspaceId ? [sessionId, workspaceId] : [sessionId]));
|
|
1387
1481
|
if (!row)
|
|
@@ -1410,7 +1504,7 @@ export class SessionRepository {
|
|
|
1410
1504
|
return tombstone();
|
|
1411
1505
|
}
|
|
1412
1506
|
restoreSession(sessionId, workspaceId) {
|
|
1413
|
-
const restore = this.
|
|
1507
|
+
const restore = this.maintainedAnalyticsTransaction(() => {
|
|
1414
1508
|
const row = this.db.prepare(`SELECT data, workspace_id FROM sessions
|
|
1415
1509
|
WHERE session_id=? ${workspaceId ? 'AND workspace_id=?' : ''}`).get(...(workspaceId ? [sessionId, workspaceId] : [sessionId]));
|
|
1416
1510
|
if (!row)
|
|
@@ -1524,6 +1618,7 @@ export class SessionRepository {
|
|
|
1524
1618
|
return rows.map((row) => JSON.parse(String(row.data)));
|
|
1525
1619
|
}
|
|
1526
1620
|
purgeSession(input) {
|
|
1621
|
+
input = redactSessionValue(input).value;
|
|
1527
1622
|
const existing = this.db.prepare('SELECT data FROM deletion_receipts WHERE operation_id=?').get(input.preview.operationId);
|
|
1528
1623
|
if (existing)
|
|
1529
1624
|
return JSON.parse(String(existing.data));
|
|
@@ -1543,7 +1638,7 @@ export class SessionRepository {
|
|
|
1543
1638
|
if (!mutationWorkspaceId) {
|
|
1544
1639
|
throw new SessionContractError('OPERATION_NOT_AUTHORIZED', 'purge mutation lacks an authorized workspace');
|
|
1545
1640
|
}
|
|
1546
|
-
const apply = this.
|
|
1641
|
+
const apply = this.maintainedAnalyticsTransaction(() => {
|
|
1547
1642
|
for (const decision of validatedDecisions) {
|
|
1548
1643
|
this.db.prepare(`INSERT INTO promotion_dependency_decisions
|
|
1549
1644
|
(operation_id, dependent_id, action, basis) VALUES (?, ?, ?, ?)`).run(input.preview.operationId, decision.dependentId, decision.action, decision.basis);
|
|
@@ -1637,7 +1732,7 @@ export class SessionRepository {
|
|
|
1637
1732
|
return apply();
|
|
1638
1733
|
}
|
|
1639
1734
|
reindex(workspaceId) {
|
|
1640
|
-
const rebuild = this.
|
|
1735
|
+
const rebuild = this.maintainedAnalyticsTransaction(() => {
|
|
1641
1736
|
let indexed = 0;
|
|
1642
1737
|
if (!workspaceId) {
|
|
1643
1738
|
this.db.exec('REINDEX');
|