@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,11 +1,10 @@
|
|
|
1
|
-
import { mkdir, readFile, rename, rm,
|
|
1
|
+
import { mkdir, readFile, rename, rm, writeFile, } from 'node:fs/promises';
|
|
2
2
|
import { hostname } from 'node:os';
|
|
3
3
|
import { dirname } from 'node:path';
|
|
4
4
|
const DEFAULTS = {
|
|
5
5
|
waitMs: 5_000,
|
|
6
6
|
pollMs: 50,
|
|
7
7
|
heartbeatMs: 1_000,
|
|
8
|
-
staleMs: 30_000,
|
|
9
8
|
};
|
|
10
9
|
export class ImportLeaseContentionError extends Error {
|
|
11
10
|
owner;
|
|
@@ -29,12 +28,13 @@ export async function acquireImportLease(databasePath, runId, options = {}) {
|
|
|
29
28
|
const waitMs = options.waitMs ?? DEFAULTS.waitMs;
|
|
30
29
|
const pollMs = options.pollMs ?? DEFAULTS.pollMs;
|
|
31
30
|
const heartbeatMs = options.heartbeatMs ?? DEFAULTS.heartbeatMs;
|
|
32
|
-
const staleMs = options.staleMs ?? DEFAULTS.staleMs;
|
|
33
31
|
const now = options.now ?? (() => new Date());
|
|
34
32
|
const processAlive = options.processAlive ?? defaultProcessAlive;
|
|
33
|
+
const processStartId = options.processStartId ?? defaultProcessStartId;
|
|
35
34
|
const lockPath = importLeasePath(databasePath);
|
|
36
35
|
const ownerPath = `${lockPath}/owner.json`;
|
|
37
36
|
const deadline = Date.now() + waitMs;
|
|
37
|
+
const startId = await processStartId(process.pid);
|
|
38
38
|
await mkdir(dirname(databasePath), { recursive: true, mode: 0o700 });
|
|
39
39
|
while (true) {
|
|
40
40
|
try {
|
|
@@ -47,6 +47,7 @@ export async function acquireImportLease(databasePath, runId, options = {}) {
|
|
|
47
47
|
host: hostname(),
|
|
48
48
|
startedAt: observed,
|
|
49
49
|
heartbeatAt: observed,
|
|
50
|
+
...(startId === null ? {} : { processStartId: startId }),
|
|
50
51
|
};
|
|
51
52
|
await writeOwner(ownerPath, owner);
|
|
52
53
|
let heartbeatWrite = Promise.resolve();
|
|
@@ -78,10 +79,10 @@ export async function acquireImportLease(databasePath, runId, options = {}) {
|
|
|
78
79
|
if (!isNodeError(error) || error.code !== 'EEXIST')
|
|
79
80
|
throw error;
|
|
80
81
|
const existing = await readOwner(ownerPath);
|
|
81
|
-
if (await staleLease(
|
|
82
|
+
if (await staleLease(existing, processAlive, processStartId)) {
|
|
82
83
|
const confirmed = await readOwner(ownerPath);
|
|
83
84
|
if (sameLease(existing, confirmed)
|
|
84
|
-
&& await staleLease(
|
|
85
|
+
&& await staleLease(confirmed, processAlive, processStartId)) {
|
|
85
86
|
await rm(lockPath, { recursive: true, force: true });
|
|
86
87
|
continue;
|
|
87
88
|
}
|
|
@@ -103,8 +104,9 @@ async function readOwner(path) {
|
|
|
103
104
|
const value = JSON.parse(await readFile(path, 'utf8'));
|
|
104
105
|
if (value.contractVersion !== '1.0.0'
|
|
105
106
|
|| typeof value.runId !== 'string'
|
|
106
|
-
||
|
|
107
|
+
|| !Number.isSafeInteger(value.pid) || (value.pid ?? 0) <= 0
|
|
107
108
|
|| typeof value.host !== 'string'
|
|
109
|
+
|| (value.processStartId !== undefined && typeof value.processStartId !== 'string')
|
|
108
110
|
|| typeof value.startedAt !== 'string'
|
|
109
111
|
|| typeof value.heartbeatAt !== 'string')
|
|
110
112
|
return null;
|
|
@@ -114,20 +116,15 @@ async function readOwner(path) {
|
|
|
114
116
|
return null;
|
|
115
117
|
}
|
|
116
118
|
}
|
|
117
|
-
async function staleLease(
|
|
119
|
+
async function staleLease(owner, processAlive, processStartId) {
|
|
118
120
|
if (!owner || owner.host !== hostname())
|
|
119
121
|
return false;
|
|
120
|
-
if (processAlive(owner.pid))
|
|
121
|
-
return
|
|
122
|
-
|
|
123
|
-
if (Number.isFinite(heartbeat))
|
|
124
|
-
return Date.now() - heartbeat > staleMs;
|
|
125
|
-
try {
|
|
126
|
-
return Date.now() - (await stat(lockPath)).mtimeMs > staleMs;
|
|
127
|
-
}
|
|
128
|
-
catch {
|
|
122
|
+
if (!processAlive(owner.pid))
|
|
123
|
+
return true;
|
|
124
|
+
if (!owner.processStartId)
|
|
129
125
|
return false;
|
|
130
|
-
|
|
126
|
+
const current = await processStartId(owner.pid);
|
|
127
|
+
return current !== null && current !== owner.processStartId;
|
|
131
128
|
}
|
|
132
129
|
function sameLease(first, second) {
|
|
133
130
|
if (!first || !second)
|
|
@@ -136,6 +133,7 @@ function sameLease(first, second) {
|
|
|
136
133
|
&& first.pid === second.pid
|
|
137
134
|
&& first.host === second.host
|
|
138
135
|
&& first.startedAt === second.startedAt
|
|
136
|
+
&& first.processStartId === second.processStartId
|
|
139
137
|
&& first.heartbeatAt === second.heartbeatAt;
|
|
140
138
|
}
|
|
141
139
|
function defaultProcessAlive(pid) {
|
|
@@ -144,7 +142,25 @@ function defaultProcessAlive(pid) {
|
|
|
144
142
|
return true;
|
|
145
143
|
}
|
|
146
144
|
catch (error) {
|
|
147
|
-
return isNodeError(error)
|
|
145
|
+
return !isNodeError(error) || error.code !== 'ESRCH';
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
async function defaultProcessStartId(pid) {
|
|
149
|
+
if (process.platform !== 'linux')
|
|
150
|
+
return null;
|
|
151
|
+
try {
|
|
152
|
+
const [details, bootId] = await Promise.all([
|
|
153
|
+
readFile(`/proc/${pid}/stat`, 'utf8'),
|
|
154
|
+
readFile('/proc/sys/kernel/random/boot_id', 'utf8'),
|
|
155
|
+
]);
|
|
156
|
+
// The command name may contain spaces and parentheses; field 22 is starttime.
|
|
157
|
+
const startTicks = details.slice(details.lastIndexOf(')') + 2).split(/\s+/)[19];
|
|
158
|
+
return startTicks && /^\d+$/.test(startTicks) && bootId.trim()
|
|
159
|
+
? `${bootId.trim()}:${startTicks}`
|
|
160
|
+
: null;
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
return null;
|
|
148
164
|
}
|
|
149
165
|
}
|
|
150
166
|
function isNodeError(error) {
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { SessionContractError } from './contracts.js';
|
|
2
|
+
export const DEFAULT_IMPORT_BYTE_LIMITS = Object.freeze({
|
|
3
|
+
maxRecordBytes: 64 * 1024 * 1024,
|
|
4
|
+
maxTotalBytes: 1024 * 1024 * 1024,
|
|
5
|
+
});
|
|
6
|
+
export function resolveImportLimits(config, flags, env = process.env) {
|
|
7
|
+
const resolve = (setting, flag, fallback) => {
|
|
8
|
+
const environmentValue = env[`AIWG_SESSIONS_IMPORT_${setting.toUpperCase()}`];
|
|
9
|
+
const origin = flag !== undefined ? 'flag' : environmentValue !== undefined ? 'env'
|
|
10
|
+
: config?.[setting] !== undefined ? 'config' : 'default';
|
|
11
|
+
const input = flag ?? environmentValue ?? config?.[setting] ?? fallback;
|
|
12
|
+
const value = typeof input === 'string' && /^\d+$/.test(input) ? Number(input) : input;
|
|
13
|
+
if (typeof value !== 'number' || !Number.isSafeInteger(value)
|
|
14
|
+
|| value < (setting === 'max_source_bytes' ? 0 : 1)) {
|
|
15
|
+
throw new SessionContractError('INVALID_ARGUMENT', `sessions.import.${setting} (${origin}) must be ${setting === 'max_source_bytes' ? 'a non-negative' : 'a positive'} safe integer in bytes`);
|
|
16
|
+
}
|
|
17
|
+
return { value, origin };
|
|
18
|
+
};
|
|
19
|
+
const record = resolve('max_record_bytes', flags?.maxRecordBytes, DEFAULT_IMPORT_BYTE_LIMITS.maxRecordBytes);
|
|
20
|
+
const source = resolve('max_source_bytes', flags?.maxSourceBytes, DEFAULT_IMPORT_BYTE_LIMITS.maxTotalBytes);
|
|
21
|
+
return {
|
|
22
|
+
maxRecordBytes: record.value,
|
|
23
|
+
maxTotalBytes: source.value,
|
|
24
|
+
limitOrigins: { maxRecordBytes: record.origin, maxTotalBytes: source.origin },
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export function assertImportByteLimit(limit, limits, observed) {
|
|
28
|
+
const configured = limits[limit];
|
|
29
|
+
if (limit === 'maxTotalBytes' && configured === 0)
|
|
30
|
+
return;
|
|
31
|
+
if (observed > configured) {
|
|
32
|
+
const setting = limit === 'maxRecordBytes' ? 'sessions.import.max_record_bytes' : 'sessions.import.max_source_bytes';
|
|
33
|
+
const origin = limits.limitOrigins?.[limit] ?? 'default';
|
|
34
|
+
throw new SessionContractError('RESOURCE_LIMIT_EXCEEDED', `${setting} exceeded (configured=${configured}, observed=${observed}, origin=${origin})`, { limit, setting, configured, observed, origin });
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=import-limits.js.map
|
|
@@ -1,18 +1,20 @@
|
|
|
1
|
-
import { SESSION_CONTRACT_VERSION, SessionEventSchema, SessionSchema, assertSupportedSchemaMajor, sha256, stableEventId, stableSessionId, SessionContractError, } from './contracts.js';
|
|
2
|
-
import {
|
|
1
|
+
import { SESSION_CONTRACT_VERSION, SessionEventSchema, SessionSchema, assertSupportedSchemaMajor, sha256, stableEventId, stableSessionId, SessionContractError, schemaIssueDetail, assertSessionResourceLimit, } from './contracts.js';
|
|
2
|
+
import { assertImportByteLimit, DEFAULT_IMPORT_BYTE_LIMITS, resolveImportLimits } from './import-limits.js';
|
|
3
|
+
import { redactSessionValue, sanitizeSessionEvent, sanitizeNativeExtensions } from './policy.js';
|
|
3
4
|
import { fingerprintSourcePrefix } from './readers.js';
|
|
5
|
+
import { DEFAULT_INACTIVITY_THRESHOLD_MS } from './lifecycle.js';
|
|
4
6
|
import { classifySessionEventOrigin, deriveSessionIntent, } from './origin.js';
|
|
5
|
-
const
|
|
7
|
+
export const DEFAULT_IMPORT_LIMITS = {
|
|
6
8
|
maxRecords: 1_000_000,
|
|
7
|
-
|
|
8
|
-
maxTotalBytes: 1024 * 1024 * 1024,
|
|
9
|
+
...DEFAULT_IMPORT_BYTE_LIMITS,
|
|
9
10
|
batchSize: 1_000,
|
|
10
11
|
};
|
|
11
12
|
export class SessionImportFailure extends SessionContractError {
|
|
12
13
|
failureReceipt;
|
|
13
14
|
constructor(failureReceipt, cause) {
|
|
14
|
-
super(cause instanceof SessionContractError ? cause.code : 'IMPORT_INTERRUPTED', cause instanceof Error ? cause.message : 'session import failed');
|
|
15
|
+
super(cause instanceof SessionContractError ? cause.code : 'IMPORT_INTERRUPTED', cause instanceof Error ? cause.message : 'session import failed', cause instanceof SessionContractError ? cause.detail : undefined);
|
|
15
16
|
this.failureReceipt = failureReceipt;
|
|
17
|
+
this.failureReceipt = redactSessionValue(failureReceipt).value;
|
|
16
18
|
this.name = 'SessionImportFailure';
|
|
17
19
|
}
|
|
18
20
|
}
|
|
@@ -30,7 +32,9 @@ export class IncrementalSessionImporter {
|
|
|
30
32
|
if (request.workspaceId !== request.selectedSource.authorizedScope.workspaceId) {
|
|
31
33
|
throw new SessionContractError('SOURCE_NOT_AUTHORIZED', 'session import workspace is outside the authorized source scope');
|
|
32
34
|
}
|
|
33
|
-
const limits = { ...
|
|
35
|
+
const limits = { ...DEFAULT_IMPORT_LIMITS, ...resolveImportLimits(undefined, {
|
|
36
|
+
maxRecordBytes: request.limits?.maxRecordBytes, maxSourceBytes: request.limits?.maxTotalBytes,
|
|
37
|
+
}), ...request.limits };
|
|
34
38
|
const previous = request.batchRunId
|
|
35
39
|
? this.repository.getBatchCheckpoint(request.source.sourceId, request.adapter.adapterVersion, request.batchRunId) ?? this.repository.getCheckpoint(request.source.sourceId, request.adapter.adapterVersion)
|
|
36
40
|
: this.repository.getCheckpoint(request.source.sourceId, request.adapter.adapterVersion);
|
|
@@ -40,17 +44,17 @@ export class IncrementalSessionImporter {
|
|
|
40
44
|
: undefined;
|
|
41
45
|
const sourceGeneration = continuity?.sourceGeneration ?? sourceGenerationDigest(request);
|
|
42
46
|
if (previous?.sourceGeneration && previous.sourceGeneration !== sourceGeneration) {
|
|
43
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'session source generation changed; explicit restart or migration is required');
|
|
47
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'session source generation changed; explicit restart or migration is required', schemaIssueDetail('sourceGeneration'));
|
|
44
48
|
}
|
|
45
49
|
if (previous?.adapterVersion && previous.adapterVersion !== request.adapter.adapterVersion) {
|
|
46
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'session checkpoint adapter version changed; checkpoint migration is required');
|
|
50
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'session checkpoint adapter version changed; checkpoint migration is required', schemaIssueDetail('adapterVersion'));
|
|
47
51
|
}
|
|
48
52
|
if (previous?.sourceSchemaVersion
|
|
49
53
|
&& previous.sourceSchemaVersion !== request.source.sourceSchemaVersion) {
|
|
50
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'session checkpoint source schema changed; checkpoint migration is required');
|
|
54
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'session checkpoint source schema changed; checkpoint migration is required', schemaIssueDetail('sourceSchemaVersion'));
|
|
51
55
|
}
|
|
52
56
|
if (previous?.policyVersion && previous.policyVersion !== request.policyVersion) {
|
|
53
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'session checkpoint policy version changed; checkpoint migration is required');
|
|
57
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'session checkpoint policy version changed; checkpoint migration is required', schemaIssueDetail('policyVersion'));
|
|
54
58
|
}
|
|
55
59
|
const checkpoint = {
|
|
56
60
|
cursor: previous?.cursor ?? '',
|
|
@@ -76,6 +80,7 @@ export class IncrementalSessionImporter {
|
|
|
76
80
|
};
|
|
77
81
|
const receipts = [];
|
|
78
82
|
let batch = [];
|
|
83
|
+
let batchBytes = 0;
|
|
79
84
|
let batchStart = checkpoint.recordsRead;
|
|
80
85
|
let durableCheckpoint = { ...checkpoint };
|
|
81
86
|
const importStarted = performance.now();
|
|
@@ -87,12 +92,14 @@ export class IncrementalSessionImporter {
|
|
|
87
92
|
if (request.signal?.aborted) {
|
|
88
93
|
throw new SessionContractError('IMPORT_INTERRUPTED', 'session import was cancelled at a durable batch boundary');
|
|
89
94
|
}
|
|
95
|
+
const identities = batch.map(recordIdentity);
|
|
96
|
+
const batchDigests = identities.map(identity => identity.digest);
|
|
90
97
|
const runId = sha256([
|
|
91
98
|
request.source.sourceId, request.adapter.adapterVersion,
|
|
92
99
|
batchStart, checkpoint.recordsRead,
|
|
93
|
-
...
|
|
100
|
+
...batchDigests,
|
|
94
101
|
].join('\0'));
|
|
95
|
-
const normalized = normalizeBatch(request, batch, runId, sourceObservedAt);
|
|
102
|
+
const normalized = normalizeBatch(request, batch, batchDigests, runId, sourceObservedAt);
|
|
96
103
|
const run = {
|
|
97
104
|
contractVersion: SESSION_CONTRACT_VERSION,
|
|
98
105
|
importRunId: runId,
|
|
@@ -123,7 +130,7 @@ export class IncrementalSessionImporter {
|
|
|
123
130
|
receipt.metrics = {
|
|
124
131
|
records: batch.length,
|
|
125
132
|
normalizedEvents: normalized.events.length,
|
|
126
|
-
normalizedBytes:
|
|
133
|
+
normalizedBytes: identities.reduce((bytes, identity) => bytes + identity.bytes, 0),
|
|
127
134
|
durationMs: performance.now() - importStarted,
|
|
128
135
|
batchLatencyMs: performance.now() - flushStarted,
|
|
129
136
|
heapUsedBytes: peakHeap,
|
|
@@ -133,20 +140,26 @@ export class IncrementalSessionImporter {
|
|
|
133
140
|
receipts.push(receipt);
|
|
134
141
|
durableCheckpoint = { ...checkpoint };
|
|
135
142
|
batch = [];
|
|
143
|
+
batchBytes = 0;
|
|
136
144
|
batchStart = checkpoint.recordsRead;
|
|
137
145
|
};
|
|
138
146
|
try {
|
|
147
|
+
if (continuity)
|
|
148
|
+
assertImportByteLimit('maxTotalBytes', limits, continuity.size);
|
|
139
149
|
for await (const record of request.adapter.stream(request.selectedSource, previous ? { value: previous.cursor } : undefined)) {
|
|
140
150
|
if (request.signal?.aborted) {
|
|
141
151
|
throw new SessionContractError('IMPORT_INTERRUPTED', 'session import was cancelled and can resume from its durable checkpoint');
|
|
142
152
|
}
|
|
143
|
-
const bytes =
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
153
|
+
const bytes = recordBytes(record);
|
|
154
|
+
assertImportByteLimit('maxRecordBytes', limits, bytes);
|
|
155
|
+
if (!continuity)
|
|
156
|
+
assertImportByteLimit('maxTotalBytes', limits, checkpoint.bytesRead + bytes);
|
|
157
|
+
assertSessionResourceLimit('maxRecords', limits.maxRecords, checkpoint.recordsRead + 1);
|
|
158
|
+
// Bound batches by bytes as well as record count for large records.
|
|
159
|
+
if (batchBytes + bytes > 4 * 1024 * 1024)
|
|
160
|
+
flush();
|
|
149
161
|
batch.push(record);
|
|
162
|
+
batchBytes += bytes;
|
|
150
163
|
checkpoint.recordsRead += 1;
|
|
151
164
|
if (record.sourceCursor?.startsWith('byte:')) {
|
|
152
165
|
checkpoint.positionKind = 'byte-offset';
|
|
@@ -195,6 +208,7 @@ export class IncrementalSessionImporter {
|
|
|
195
208
|
: durableCheckpoint,
|
|
196
209
|
errorCode: error instanceof SessionContractError
|
|
197
210
|
? error.code : 'IMPORT_INTERRUPTED',
|
|
211
|
+
detail: error instanceof SessionContractError ? error.detail : undefined,
|
|
198
212
|
}, error);
|
|
199
213
|
}
|
|
200
214
|
if (request.publish !== false && request.source.consistency === 'complete') {
|
|
@@ -207,20 +221,30 @@ export class IncrementalSessionImporter {
|
|
|
207
221
|
return receipts;
|
|
208
222
|
}
|
|
209
223
|
}
|
|
210
|
-
|
|
224
|
+
/** Keep large temporary JSON strings out of the asynchronous import frame. */
|
|
225
|
+
function recordBytes(record) {
|
|
226
|
+
return Buffer.byteLength(JSON.stringify(record));
|
|
227
|
+
}
|
|
228
|
+
/** Compute flush-time identity once, preserving adapters that mutate yielded objects. */
|
|
229
|
+
function recordIdentity(record) {
|
|
230
|
+
const serialized = JSON.stringify(record);
|
|
231
|
+
return { bytes: Buffer.byteLength(serialized), digest: sha256(serialized) };
|
|
232
|
+
}
|
|
233
|
+
function normalizeBatch(request, records, digests, importRunId, sourceObservedAt) {
|
|
211
234
|
const sessions = new Map();
|
|
212
|
-
const events = records.map((record) => {
|
|
235
|
+
const events = records.map((record, index) => {
|
|
213
236
|
const sessionId = stableSessionId(request.source.provider, request.source.sourceId, record.nativeSessionId);
|
|
214
|
-
const redacted = redactSessionText(record.text);
|
|
215
237
|
const native = sanitizeNativeExtensions(record.extensions ?? {});
|
|
216
|
-
const
|
|
238
|
+
const lineage = request.source.provider === 'codex' && native.value.lineage
|
|
239
|
+
? { lineage: native.value.lineage } : {};
|
|
240
|
+
const digest = digests[index];
|
|
217
241
|
const origin = classifySessionEventOrigin(request.source.provider, record);
|
|
218
242
|
const lifecycle = sessionLifecycle(request, record, sourceObservedAt);
|
|
219
243
|
const lifecycleEvidence = sessionLifecycleEvidence(request, record, sourceObservedAt);
|
|
220
244
|
const extensions = {
|
|
221
|
-
[`native.${request.source.provider}`]:
|
|
245
|
+
[`native.${request.source.provider}`]: record.extensions ?? {},
|
|
222
246
|
};
|
|
223
|
-
const event = SessionEventSchema.parse({
|
|
247
|
+
const event = sanitizeSessionEvent(SessionEventSchema.parse({
|
|
224
248
|
contractVersion: SESSION_CONTRACT_VERSION,
|
|
225
249
|
eventId: stableEventId(request.source.provider, request.source.sourceId, record, digest),
|
|
226
250
|
sessionId, sourceId: request.source.sourceId, importRunId,
|
|
@@ -238,17 +262,13 @@ function normalizeBatch(request, records, importRunId, sourceObservedAt) {
|
|
|
238
262
|
model: record.model ?? null,
|
|
239
263
|
entities: record.entities ?? [],
|
|
240
264
|
extractionState: record.extractionState ?? null,
|
|
241
|
-
searchableText:
|
|
265
|
+
searchableText: record.text, digest, rawReference: record.rawReference,
|
|
242
266
|
adapterVersion: request.adapter.adapterVersion,
|
|
243
267
|
consistency: request.source.consistency,
|
|
244
|
-
sensitivity: {
|
|
245
|
-
classification: redacted.sensitivity === 'sensitive' || native.sensitivity === 'sensitive'
|
|
246
|
-
? 'sensitive' : 'none',
|
|
247
|
-
classes: [...new Set([...redacted.classes, ...native.classes])].sort(),
|
|
248
|
-
},
|
|
268
|
+
sensitivity: { classification: 'none', classes: [] },
|
|
249
269
|
opaque: !isKnownEventKind(record.kind),
|
|
250
270
|
extensions,
|
|
251
|
-
});
|
|
271
|
+
}));
|
|
252
272
|
if (!sessions.has(sessionId)) {
|
|
253
273
|
sessions.set(sessionId, SessionSchema.parse({
|
|
254
274
|
contractVersion: SESSION_CONTRACT_VERSION,
|
|
@@ -260,6 +280,7 @@ function normalizeBatch(request, records, importRunId, sourceObservedAt) {
|
|
|
260
280
|
sourceDigest: sha256(`${sourceGenerationDigest(request)}\0${record.nativeSessionId}`),
|
|
261
281
|
extensions: {
|
|
262
282
|
[`native.${request.source.provider}`]: {
|
|
283
|
+
...lineage,
|
|
263
284
|
lifecycleEvidence,
|
|
264
285
|
},
|
|
265
286
|
},
|
|
@@ -279,6 +300,7 @@ function normalizeBatch(request, records, importRunId, sourceObservedAt) {
|
|
|
279
300
|
session.lifecycle = selected.lifecycle;
|
|
280
301
|
session.extensions[nativeKey] = {
|
|
281
302
|
...nativeRecord,
|
|
303
|
+
...lineage,
|
|
282
304
|
lifecycleEvidence: selected.evidence,
|
|
283
305
|
};
|
|
284
306
|
}
|
|
@@ -287,7 +309,7 @@ function normalizeBatch(request, records, importRunId, sourceObservedAt) {
|
|
|
287
309
|
for (const session of sessions.values()) {
|
|
288
310
|
session.intent = deriveSessionIntent(events.filter((event) => event.sessionId === session.sessionId));
|
|
289
311
|
}
|
|
290
|
-
return { sessions: [...sessions.values()], events };
|
|
312
|
+
return { sessions: redactSessionValue([...sessions.values()]).value, events };
|
|
291
313
|
}
|
|
292
314
|
const KNOWN_EVENT_KINDS = new Set(['message', 'tool-call', 'tool-result', 'artifact', 'attachment', 'summary']);
|
|
293
315
|
function isKnownEventKind(kind) {
|
|
@@ -363,6 +385,7 @@ function sessionLifecycleEvidence(request, record, sourceObservedAt) {
|
|
|
363
385
|
state: 'active',
|
|
364
386
|
observedAt: observedAt ?? request.source.authorizedAt,
|
|
365
387
|
confidence: 'provisional',
|
|
388
|
+
thresholdMs,
|
|
366
389
|
};
|
|
367
390
|
}
|
|
368
391
|
function nativeLifecycle(extensions) {
|
|
@@ -416,7 +439,6 @@ function evidenceTimestamp(value) {
|
|
|
416
439
|
const parsed = Date.parse(String(value.observedAt ?? ''));
|
|
417
440
|
return Number.isFinite(parsed) ? parsed : Number.NEGATIVE_INFINITY;
|
|
418
441
|
}
|
|
419
|
-
const DEFAULT_INACTIVITY_THRESHOLD_MS = 24 * 60 * 60 * 1000;
|
|
420
442
|
function inactivityThresholdMs(request) {
|
|
421
443
|
return request.inactivityThresholdMs ?? DEFAULT_INACTIVITY_THRESHOLD_MS;
|
|
422
444
|
}
|
|
@@ -454,15 +476,15 @@ async function sourceContinuity(request, previous) {
|
|
|
454
476
|
const metadata = await fingerprintSourcePrefix(authorization, 0);
|
|
455
477
|
if (!isSnapshot && previous?.sourceSize !== undefined) {
|
|
456
478
|
if (metadata.size < previous.sourceSize) {
|
|
457
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'session source was truncated before its durable checkpoint');
|
|
479
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'session source was truncated before its durable checkpoint', schemaIssueDetail('sourceSize'));
|
|
458
480
|
}
|
|
459
481
|
if (previous.sourceFileIdentity
|
|
460
482
|
&& previous.sourceFileIdentity !== metadata.fileIdentity) {
|
|
461
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'session source file generation was replaced or rotated');
|
|
483
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'session source file generation was replaced or rotated', schemaIssueDetail('sourceFileIdentity'));
|
|
462
484
|
}
|
|
463
485
|
const priorPrefix = await fingerprintSourcePrefix(authorization, previous.sourceSize, skipPrefixBytes);
|
|
464
486
|
if (previous.prefixDigest && priorPrefix.digest !== previous.prefixDigest) {
|
|
465
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'session source prefix was rewritten before its durable checkpoint');
|
|
487
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'session source prefix was rewritten before its durable checkpoint', schemaIssueDetail('prefixDigest'));
|
|
466
488
|
}
|
|
467
489
|
}
|
|
468
490
|
const current = await fingerprintSourcePrefix(authorization, metadata.size, skipPrefixBytes);
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export const DEFAULT_INACTIVITY_THRESHOLD_MS = 24 * 60 * 60 * 1000;
|
|
2
|
+
export function effectiveSessionLifecycle(session) {
|
|
3
|
+
if (session.lifecycle !== 'active' && session.lifecycle !== 'inactive')
|
|
4
|
+
return session;
|
|
5
|
+
const nativeKey = `native.${session.provider}`;
|
|
6
|
+
const native = objectRecord(session.extensions[nativeKey]);
|
|
7
|
+
const evidence = objectRecord(native.lifecycleEvidence);
|
|
8
|
+
if (evidence.basis !== 'open-provisional-source'
|
|
9
|
+
&& evidence.basis !== 'inactivity-threshold')
|
|
10
|
+
return session;
|
|
11
|
+
const observedAt = session.updatedAt ?? evidence.observedAt;
|
|
12
|
+
const timestamp = typeof observedAt === 'string' ? Date.parse(observedAt) : NaN;
|
|
13
|
+
if (!Number.isFinite(timestamp))
|
|
14
|
+
return session;
|
|
15
|
+
const thresholdMs = typeof evidence.thresholdMs === 'number'
|
|
16
|
+
&& Number.isFinite(evidence.thresholdMs)
|
|
17
|
+
&& evidence.thresholdMs >= 0
|
|
18
|
+
? evidence.thresholdMs : DEFAULT_INACTIVITY_THRESHOLD_MS;
|
|
19
|
+
const inactive = Date.now() - timestamp > thresholdMs;
|
|
20
|
+
const lifecycle = inactive ? 'inactive' : 'active';
|
|
21
|
+
return {
|
|
22
|
+
...session,
|
|
23
|
+
lifecycle,
|
|
24
|
+
extensions: {
|
|
25
|
+
...session.extensions,
|
|
26
|
+
[nativeKey]: {
|
|
27
|
+
...native,
|
|
28
|
+
lifecycleEvidence: {
|
|
29
|
+
...evidence,
|
|
30
|
+
basis: inactive ? 'inactivity-threshold' : 'open-provisional-source',
|
|
31
|
+
state: lifecycle,
|
|
32
|
+
observedAt,
|
|
33
|
+
confidence: inactive ? 'medium' : 'provisional',
|
|
34
|
+
thresholdMs,
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function objectRecord(value) {
|
|
41
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
42
|
+
? value
|
|
43
|
+
: {};
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=lifecycle.js.map
|