@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,7 @@
|
|
|
1
1
|
import { basename } from 'node:path';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { SessionContractError, assertSupportedSchemaMajor, } from '../contracts.js';
|
|
4
|
-
import {
|
|
3
|
+
import { schemaRejectionDetail, schemaIssueDetail, SessionContractError, assertSupportedSchemaMajor, } from '../contracts.js';
|
|
4
|
+
import { streamBoundedJsonLines, } from '../readers.js';
|
|
5
5
|
export const DEVIN_DESKTOP_ADAPTER_VERSION = '1.1.0';
|
|
6
6
|
export const DEVIN_DESKTOP_TRANSCRIPT_SCHEMA_VERSION = '1.0.0';
|
|
7
7
|
/** @deprecated Compatibility export. */
|
|
@@ -38,19 +38,14 @@ export class DevinDesktopSessionAdapter {
|
|
|
38
38
|
// Deliberately empty: hook enablement and transcript selection are explicit user actions.
|
|
39
39
|
}
|
|
40
40
|
async inspect(source) {
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
};
|
|
41
|
+
const records = this.stream(source);
|
|
42
|
+
let result = await records.next();
|
|
43
|
+
while (!result.done)
|
|
44
|
+
result = await records.next();
|
|
45
|
+
return result.value;
|
|
47
46
|
}
|
|
48
47
|
async *stream(source, cursor) {
|
|
49
|
-
|
|
50
|
-
// Preserve the precise unsupported-operation diagnostics.
|
|
51
|
-
await this.readSource(source);
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
48
|
+
this.assertSupportedLocator(source);
|
|
54
49
|
const start = parseCursor(cursor?.value);
|
|
55
50
|
const input = await streamBoundedJsonLines({
|
|
56
51
|
selectedPath: source.locator,
|
|
@@ -62,12 +57,12 @@ export class DevinDesktopSessionAdapter {
|
|
|
62
57
|
for await (const line of input) {
|
|
63
58
|
const parsed = StepSchema.safeParse(line.value);
|
|
64
59
|
if (!parsed.success) {
|
|
65
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'Windsurf transcript step is malformed');
|
|
60
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'Windsurf transcript step is malformed', schemaRejectionDetail(parsed.error));
|
|
66
61
|
}
|
|
67
62
|
const step = parsed.data;
|
|
68
63
|
const currentVersion = step.schema_version ?? DEVIN_DESKTOP_TRANSCRIPT_SCHEMA_VERSION;
|
|
69
64
|
if (schemaVersion && schemaVersion !== currentVersion) {
|
|
70
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'mixed Windsurf transcript schemas');
|
|
65
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'mixed Windsurf transcript schemas', schemaIssueDetail('schema_version'));
|
|
71
66
|
}
|
|
72
67
|
schemaVersion = currentVersion;
|
|
73
68
|
assertSupportedSchemaMajor(schemaVersion);
|
|
@@ -75,7 +70,7 @@ export class DevinDesktopSessionAdapter {
|
|
|
75
70
|
?? nativeSessionId
|
|
76
71
|
?? basename(source.locator, '.jsonl');
|
|
77
72
|
if (step.trajectory_id && nativeSessionId && step.trajectory_id !== nativeSessionId) {
|
|
78
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'mixed Windsurf trajectory identities');
|
|
73
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'mixed Windsurf trajectory identities', schemaIssueDetail('trajectory_id'));
|
|
79
74
|
}
|
|
80
75
|
nativeSessionId = currentSession;
|
|
81
76
|
if (seen++ < start)
|
|
@@ -83,45 +78,21 @@ export class DevinDesktopSessionAdapter {
|
|
|
83
78
|
yield normalizeStep(step, currentSession, line.sequence, line.byteOffset, canonicalLocatorClass(source.locatorClass), schemaVersion);
|
|
84
79
|
}
|
|
85
80
|
if (seen === 0) {
|
|
86
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'Windsurf transcript is empty or malformed');
|
|
81
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'Windsurf transcript is empty or malformed', schemaIssueDetail('<root>'));
|
|
87
82
|
}
|
|
83
|
+
return {
|
|
84
|
+
sourceSchemaVersion: schemaVersion,
|
|
85
|
+
consistency: 'provisional',
|
|
86
|
+
operationalState: 'available',
|
|
87
|
+
};
|
|
88
88
|
}
|
|
89
|
-
|
|
89
|
+
assertSupportedLocator(source) {
|
|
90
90
|
if (isLegacyLocator(source.locatorClass)) {
|
|
91
91
|
throw new SessionContractError('UNSUPPORTED_OPERATION', 'legacy Devin Desktop/Windsurf protobuf stores are unsupported; enable post_cascade_response_with_transcript and select its JSONL output');
|
|
92
92
|
}
|
|
93
93
|
if (!isCurrentHookLocator(source.locatorClass)) {
|
|
94
94
|
throw new SessionContractError('UNSUPPORTED_OPERATION', 'Devin Desktop (Windsurf compatibility) requires an explicitly selected post_cascade_response_with_transcript JSONL file');
|
|
95
95
|
}
|
|
96
|
-
const input = await readBoundedJsonLines({
|
|
97
|
-
selectedPath: source.locator,
|
|
98
|
-
allowedRoots: source.authorizedScope.allowedRoots,
|
|
99
|
-
}, { consistency: 'provisional', limits: this.limits });
|
|
100
|
-
if (input.records.length === 0) {
|
|
101
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'Windsurf transcript is empty or malformed');
|
|
102
|
-
}
|
|
103
|
-
const steps = input.records.map((record) => {
|
|
104
|
-
const parsed = StepSchema.safeParse(record.value);
|
|
105
|
-
if (!parsed.success) {
|
|
106
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'Windsurf transcript step is malformed');
|
|
107
|
-
}
|
|
108
|
-
return { ...record, value: parsed.data };
|
|
109
|
-
});
|
|
110
|
-
const versions = new Set(steps.map(({ value }) => value.schema_version ?? DEVIN_DESKTOP_TRANSCRIPT_SCHEMA_VERSION));
|
|
111
|
-
if (versions.size !== 1) {
|
|
112
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'mixed Windsurf transcript schemas');
|
|
113
|
-
}
|
|
114
|
-
const schemaVersion = [...versions][0];
|
|
115
|
-
assertSupportedSchemaMajor(schemaVersion);
|
|
116
|
-
const trajectoryIds = new Set(steps.flatMap(({ value }) => value.trajectory_id ? [value.trajectory_id] : []));
|
|
117
|
-
if (trajectoryIds.size > 1) {
|
|
118
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'mixed Windsurf trajectory identities');
|
|
119
|
-
}
|
|
120
|
-
const nativeSessionId = [...trajectoryIds][0] ?? basename(source.locator, '.jsonl');
|
|
121
|
-
return {
|
|
122
|
-
schemaVersion,
|
|
123
|
-
records: steps.map(({ value, sequence, byteOffset }) => normalizeStep(value, nativeSessionId, sequence, byteOffset, canonicalLocatorClass(source.locatorClass), schemaVersion)),
|
|
124
|
-
};
|
|
125
96
|
}
|
|
126
97
|
}
|
|
127
98
|
/** @deprecated Use DevinDesktopSessionAdapter; retained through the alias window. */
|
|
@@ -206,7 +177,7 @@ function parseCursor(value) {
|
|
|
206
177
|
if (!value)
|
|
207
178
|
return 0;
|
|
208
179
|
if (!/^\d+$/.test(value))
|
|
209
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'invalid Windsurf cursor');
|
|
180
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'invalid Windsurf cursor', schemaIssueDetail('cursor'));
|
|
210
181
|
return Number(value);
|
|
211
182
|
}
|
|
212
183
|
//# sourceMappingURL=windsurf.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { reconcileCoveragePreflight } from './coverage-preflight.js';
|
|
2
|
-
export const BATCH_IMPORT_VERSION = '
|
|
3
|
-
export const COVERAGE_VERSION = '
|
|
2
|
+
export const BATCH_IMPORT_VERSION = '2.0.0';
|
|
3
|
+
export const COVERAGE_VERSION = '2.0.0';
|
|
4
4
|
export function coverageFromBatchRun(run, now = new Date(), staleAfterMs = 24 * 60 * 60 * 1_000) {
|
|
5
5
|
if (!run)
|
|
6
6
|
return unknownCoverage();
|
|
@@ -9,6 +9,7 @@ export function coverageFromBatchRun(run, now = new Date(), staleAfterMs = 24 *
|
|
|
9
9
|
]);
|
|
10
10
|
const accepted = run.sources.filter((source) => source.status === 'committed').length;
|
|
11
11
|
const rejected = run.sources.filter((source) => source.status === 'rejected').length;
|
|
12
|
+
const excluded = run.sources.filter(source => source.status === 'excluded').length;
|
|
12
13
|
const skipped = run.sources.filter((source) => source.status === 'skipped').length;
|
|
13
14
|
const duplicated = run.sources.filter((source) => source.status === 'duplicate').length;
|
|
14
15
|
const previouslyCommitted = run.sources.filter((source) => source.status === 'previously-committed').length;
|
|
@@ -20,9 +21,12 @@ export function coverageFromBatchRun(run, now = new Date(), staleAfterMs = 24 *
|
|
|
20
21
|
const manifestAgeMs = Math.max(0, now.getTime() - Date.parse(run.manifestCreatedAt));
|
|
21
22
|
const isStale = manifestAgeMs > staleAfterMs;
|
|
22
23
|
const preflight = run.preflight ? reconcileCoveragePreflight(run.preflight, run.sources) : undefined;
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
const unresolvedProviders = preflight?.unresolvedProviders
|
|
25
|
+
?? [...new Set([...unavailable, ...exportRequired, ...notChecked])].sort();
|
|
26
|
+
const acquisitionIncomplete = rejected > 0 || pending > 0 || skipped > 0
|
|
27
|
+
|| (preflight?.expectedProviderBasis === 'explicit' && unresolvedProviders.length > 0);
|
|
28
|
+
const incomplete = acquisitionIncomplete || !preflight || preflight.status !== 'complete'
|
|
29
|
+
|| unavailable.length > 0 || accepted + duplicated + previouslyCommitted + excluded === 0
|
|
26
30
|
|| exportRequired.length > 0 || notChecked.length > 0;
|
|
27
31
|
const rejectionCounts = {};
|
|
28
32
|
for (const source of run.sources) {
|
|
@@ -54,7 +58,8 @@ export function coverageFromBatchRun(run, now = new Date(), staleAfterMs = 24 *
|
|
|
54
58
|
return {
|
|
55
59
|
schemaVersion: COVERAGE_VERSION,
|
|
56
60
|
status: isStale ? 'stale' : incomplete ? 'partial' : 'complete',
|
|
57
|
-
acquisitionStatus:
|
|
61
|
+
acquisitionStatus: acquisitionIncomplete ? 'partial' : 'complete',
|
|
62
|
+
unresolvedProviders,
|
|
58
63
|
preflight,
|
|
59
64
|
semanticReview: 'not-assessed',
|
|
60
65
|
workspaceId: run.workspaceId,
|
|
@@ -67,6 +72,7 @@ export function coverageFromBatchRun(run, now = new Date(), staleAfterMs = 24 *
|
|
|
67
72
|
discovered: run.sources.length,
|
|
68
73
|
accepted,
|
|
69
74
|
rejected,
|
|
75
|
+
excluded,
|
|
70
76
|
skipped,
|
|
71
77
|
duplicated,
|
|
72
78
|
previouslyCommitted,
|
|
@@ -74,9 +80,9 @@ export function coverageFromBatchRun(run, now = new Date(), staleAfterMs = 24 *
|
|
|
74
80
|
},
|
|
75
81
|
sessionsAccepted: run.sources.reduce((sum, source) => sum + source.sessionsAccepted, 0),
|
|
76
82
|
eventsAccepted: run.sources.reduce((sum, source) => sum + source.eventsAccepted, 0),
|
|
77
|
-
coverageRatio: run.sources.length ===
|
|
83
|
+
coverageRatio: run.sources.length === excluded
|
|
78
84
|
? null
|
|
79
|
-
: (accepted + duplicated + previouslyCommitted) / run.sources.length,
|
|
85
|
+
: (accepted + duplicated + previouslyCommitted) / (run.sources.length - excluded),
|
|
80
86
|
rejectionCounts,
|
|
81
87
|
sourceDateRange: {
|
|
82
88
|
earliest: sourceTimestamps.at(0) ?? null,
|
|
@@ -100,6 +106,7 @@ function unknownCoverage() {
|
|
|
100
106
|
schemaVersion: COVERAGE_VERSION,
|
|
101
107
|
status: 'unknown',
|
|
102
108
|
acquisitionStatus: 'unknown',
|
|
109
|
+
unresolvedProviders: [],
|
|
103
110
|
semanticReview: 'not-assessed',
|
|
104
111
|
workspaceId: '',
|
|
105
112
|
manifestId: null,
|
|
@@ -116,6 +123,7 @@ function unknownCoverage() {
|
|
|
116
123
|
discovered: 0,
|
|
117
124
|
accepted: 0,
|
|
118
125
|
rejected: 0,
|
|
126
|
+
excluded: 0,
|
|
119
127
|
skipped: 0,
|
|
120
128
|
duplicated: 0,
|
|
121
129
|
previouslyCommitted: 0,
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import { stat } from 'node:fs/promises';
|
|
2
2
|
import { createSessionAdapterRegistry } from './adapter-registry.js';
|
|
3
3
|
import { coveragePreflight, sessionRuntimeIdentity } from './coverage-preflight.js';
|
|
4
|
-
import { SESSION_CONTRACT_VERSION, SessionContractError, SessionSourceSchema, sha256, } from './contracts.js';
|
|
4
|
+
import { SESSION_CONTRACT_VERSION, SessionContractError, schemaIssueDetail, SessionSourceSchema, sha256, } from './contracts.js';
|
|
5
5
|
import { BATCH_IMPORT_VERSION, coverageFromBatchRun, } from './batch-contracts.js';
|
|
6
6
|
import { IncrementalSessionImporter, SessionImportFailure } from './importer.js';
|
|
7
|
+
import { matchImportExclusion, resolveImportExclusions } from './import-exclusions.js';
|
|
8
|
+
import { resolveImportLimits } from './import-limits.js';
|
|
7
9
|
import { fingerprintSourceFile } from './readers.js';
|
|
8
10
|
export async function importDiscoveryManifest(options) {
|
|
11
|
+
const exclusions = resolveImportExclusions(undefined, options.exclude);
|
|
12
|
+
const limits = { ...resolveImportLimits(undefined, {
|
|
13
|
+
maxRecordBytes: options.limits?.maxRecordBytes, maxSourceBytes: options.limits?.maxTotalBytes,
|
|
14
|
+
}), ...options.limits };
|
|
9
15
|
const now = options.now ?? (() => new Date());
|
|
10
16
|
const runId = sha256([
|
|
11
17
|
'workspace-import-v1',
|
|
@@ -17,6 +23,7 @@ export async function importDiscoveryManifest(options) {
|
|
|
17
23
|
if (run.runId !== runId) {
|
|
18
24
|
throw new SessionContractError('IMPORT_CONFLICT', 'discovery manifest is already associated with a different batch run');
|
|
19
25
|
}
|
|
26
|
+
run.schemaVersion = BATCH_IMPORT_VERSION;
|
|
20
27
|
run.preflight = coveragePreflight({
|
|
21
28
|
expectedProviders: options.manifest.preflight?.expectedProviders,
|
|
22
29
|
expectedProviderBasis: options.manifest.preflight?.expectedProviderBasis ?? 'legacy',
|
|
@@ -33,6 +40,12 @@ export async function importDiscoveryManifest(options) {
|
|
|
33
40
|
if (!disposition) {
|
|
34
41
|
throw new SessionContractError('IMPORT_CONFLICT', `batch run is missing discovered source ${manifestSource.sourceId}`);
|
|
35
42
|
}
|
|
43
|
+
const exclusion = matchImportExclusion(manifestSource, exclusions) ?? manifestSource.exclusion;
|
|
44
|
+
if (exclusion) {
|
|
45
|
+
excludeSource(disposition, exclusion, now());
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
delete disposition.exclusion;
|
|
36
49
|
if (isAccepted(disposition.status)) {
|
|
37
50
|
disposition.status = 'previously-committed';
|
|
38
51
|
disposition.updatedAt = now().toISOString();
|
|
@@ -48,6 +61,7 @@ export async function importDiscoveryManifest(options) {
|
|
|
48
61
|
disposition.attempts += 1;
|
|
49
62
|
disposition.errorCode = null;
|
|
50
63
|
disposition.diagnostic = null;
|
|
64
|
+
disposition.detail = null;
|
|
51
65
|
disposition.updatedAt = now().toISOString();
|
|
52
66
|
persistProgress(options.repository, run, now());
|
|
53
67
|
try {
|
|
@@ -62,7 +76,7 @@ export async function importDiscoveryManifest(options) {
|
|
|
62
76
|
allowedRoots: [manifestSource.authorizedRoot],
|
|
63
77
|
},
|
|
64
78
|
};
|
|
65
|
-
const adapter = adapterFor(manifestSource.provider);
|
|
79
|
+
const adapter = adapterFor(manifestSource.provider, limits);
|
|
66
80
|
const source = await sessionSource(selectedSource, adapter);
|
|
67
81
|
const receipts = await new IncrementalSessionImporter(options.repository).import({
|
|
68
82
|
source,
|
|
@@ -74,6 +88,7 @@ export async function importDiscoveryManifest(options) {
|
|
|
74
88
|
publish: false,
|
|
75
89
|
signal: options.signal,
|
|
76
90
|
inactivityThresholdMs: options.inactivityThresholdMs,
|
|
91
|
+
limits,
|
|
77
92
|
});
|
|
78
93
|
await assertManifestSourceUnchanged(manifestSource);
|
|
79
94
|
const totals = options.repository.sourceImportTotals(manifestSource.sourceId, run.runId);
|
|
@@ -89,10 +104,12 @@ export async function importDiscoveryManifest(options) {
|
|
|
89
104
|
catch (error) {
|
|
90
105
|
disposition.status = 'rejected';
|
|
91
106
|
disposition.errorCode = importErrorCode(error);
|
|
107
|
+
disposition.detail = error instanceof SessionContractError ? error.detail ?? null : null;
|
|
92
108
|
disposition.diagnostic = [
|
|
93
109
|
`provider=${manifestSource.provider}`,
|
|
94
110
|
`source=${manifestSource.sourceId}`,
|
|
95
111
|
`code=${disposition.errorCode}`,
|
|
112
|
+
...(disposition.detail ? [`detail=${JSON.stringify(disposition.detail)}`] : []),
|
|
96
113
|
].join(' ');
|
|
97
114
|
}
|
|
98
115
|
disposition.updatedAt = now().toISOString();
|
|
@@ -101,14 +118,14 @@ export async function importDiscoveryManifest(options) {
|
|
|
101
118
|
}
|
|
102
119
|
const rejected = run.sources.some((source) => source.status === 'rejected');
|
|
103
120
|
const pending = run.sources.some((source) => source.status === 'pending' || source.status === 'running');
|
|
104
|
-
const
|
|
121
|
+
const acquisitionIncomplete = coverageFromBatchRun(run, now()).acquisitionStatus !== 'complete';
|
|
105
122
|
const publishable = run.sources
|
|
106
123
|
.filter((source) => isAccepted(source.status))
|
|
107
124
|
.map((source) => source.sourceId);
|
|
108
125
|
injectFault(options, run, 'before-publication');
|
|
109
126
|
options.repository.commitStagedBatch(run.runId, publishable);
|
|
110
127
|
injectFault(options, run, 'after-publication');
|
|
111
|
-
run.status = pending ? 'interrupted' : rejected ||
|
|
128
|
+
run.status = pending ? 'interrupted' : rejected || acquisitionIncomplete ? 'partial' : 'complete';
|
|
112
129
|
run.updatedAt = now().toISOString();
|
|
113
130
|
run.completedAt = pending ? null : run.updatedAt;
|
|
114
131
|
options.repository.saveBatchImportRun(run);
|
|
@@ -128,10 +145,20 @@ function injectFault(options, run, boundary, sourceId) {
|
|
|
128
145
|
throw error;
|
|
129
146
|
}
|
|
130
147
|
}
|
|
131
|
-
export function previewDiscoveryImport(manifest, existing, now = new Date()) {
|
|
148
|
+
export function previewDiscoveryImport(manifest, existing, now = new Date(), exclude = []) {
|
|
132
149
|
const run = existing ?? newBatchRun(manifest, sha256(['workspace-import-v1', manifest.manifestId, manifest.workspaceId].join('\0')), now);
|
|
150
|
+
const exclusions = resolveImportExclusions(undefined, exclude);
|
|
133
151
|
return receiptFor({
|
|
134
152
|
...run,
|
|
153
|
+
sources: run.sources.map(source => {
|
|
154
|
+
const manifestSource = manifest.sources.find(candidate => candidate.sourceId === source.sourceId);
|
|
155
|
+
const exclusion = matchImportExclusion(manifestSource, exclusions) ?? manifestSource.exclusion;
|
|
156
|
+
if (!exclusion)
|
|
157
|
+
return source;
|
|
158
|
+
const disposition = { ...source };
|
|
159
|
+
excludeSource(disposition, exclusion, now);
|
|
160
|
+
return disposition;
|
|
161
|
+
}),
|
|
135
162
|
preflight: coveragePreflight({
|
|
136
163
|
expectedProviders: manifest.preflight?.expectedProviders,
|
|
137
164
|
expectedProviderBasis: manifest.preflight?.expectedProviderBasis ?? 'legacy',
|
|
@@ -157,7 +184,8 @@ function newBatchRun(manifest, runId, now) {
|
|
|
157
184
|
sources: manifest.sources.map((source) => ({
|
|
158
185
|
sourceId: source.sourceId,
|
|
159
186
|
provider: source.provider,
|
|
160
|
-
status: 'pending',
|
|
187
|
+
status: source.status ?? 'pending',
|
|
188
|
+
...(source.exclusion ? { exclusion: source.exclusion } : {}),
|
|
161
189
|
attempts: 0,
|
|
162
190
|
sessionsAccepted: 0,
|
|
163
191
|
eventsAccepted: 0,
|
|
@@ -173,10 +201,12 @@ function receiptFor(run, now) {
|
|
|
173
201
|
schemaVersion: BATCH_IMPORT_VERSION,
|
|
174
202
|
run,
|
|
175
203
|
coverage,
|
|
204
|
+
interruptedRuns: [],
|
|
176
205
|
totals: {
|
|
177
206
|
discovered: coverage.sources.discovered,
|
|
178
207
|
accepted: coverage.sources.accepted,
|
|
179
208
|
rejected: coverage.sources.rejected,
|
|
209
|
+
excluded: coverage.sources.excluded,
|
|
180
210
|
skipped: coverage.sources.skipped,
|
|
181
211
|
duplicated: coverage.sources.duplicated,
|
|
182
212
|
previouslyCommitted: coverage.sources.previouslyCommitted,
|
|
@@ -186,6 +216,16 @@ function receiptFor(run, now) {
|
|
|
186
216
|
},
|
|
187
217
|
};
|
|
188
218
|
}
|
|
219
|
+
function excludeSource(source, exclusion, now) {
|
|
220
|
+
source.status = 'excluded';
|
|
221
|
+
source.exclusion = exclusion;
|
|
222
|
+
source.errorCode = null;
|
|
223
|
+
source.diagnostic = null;
|
|
224
|
+
source.detail = null;
|
|
225
|
+
source.sessionsAccepted = 0;
|
|
226
|
+
source.eventsAccepted = 0;
|
|
227
|
+
source.updatedAt = now.toISOString();
|
|
228
|
+
}
|
|
189
229
|
function persistProgress(repository, run, now) {
|
|
190
230
|
run.updatedAt = now.toISOString();
|
|
191
231
|
repository.saveBatchImportRun(run);
|
|
@@ -196,21 +236,21 @@ async function assertManifestSourceUnchanged(source) {
|
|
|
196
236
|
details = await stat(source.locator);
|
|
197
237
|
}
|
|
198
238
|
catch {
|
|
199
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'discovered source is no longer available; run discovery again');
|
|
239
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'discovered source is no longer available; run discovery again', schemaIssueDetail('locator'));
|
|
200
240
|
}
|
|
201
241
|
if (details.size !== source.sizeBytes || details.mtime.toISOString() !== source.modifiedAt) {
|
|
202
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'discovered source changed after manifest creation; run discovery again');
|
|
242
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'discovered source changed after manifest creation; run discovery again', schemaIssueDetail(details.size !== source.sizeBytes ? 'sizeBytes' : 'modifiedAt'));
|
|
203
243
|
}
|
|
204
244
|
const fingerprint = await fingerprintSourceFile({
|
|
205
245
|
selectedPath: source.locator,
|
|
206
246
|
allowedRoots: [source.authorizedRoot],
|
|
207
247
|
});
|
|
208
248
|
if (fingerprint.digest !== source.digest || fingerprint.size !== source.sizeBytes) {
|
|
209
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'discovered source content changed after manifest creation; run discovery again');
|
|
249
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'discovered source content changed after manifest creation; run discovery again', schemaIssueDetail('digest'));
|
|
210
250
|
}
|
|
211
251
|
}
|
|
212
|
-
function adapterFor(provider) {
|
|
213
|
-
return createSessionAdapterRegistry().get(provider);
|
|
252
|
+
function adapterFor(provider, limits) {
|
|
253
|
+
return createSessionAdapterRegistry(limits).get(provider);
|
|
214
254
|
}
|
|
215
255
|
async function sessionSource(selected, adapter) {
|
|
216
256
|
const probe = await adapter.inspect(selected);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
+
import { redactSessionText, redactSessionValue } from './policy.js';
|
|
3
4
|
export const SESSION_CONTRACT_VERSION = '1.0.0';
|
|
4
5
|
export const SESSION_PROVIDER_IDS = [
|
|
5
6
|
'claude', 'codex', 'copilot', 'cursor', 'factory', 'hermes',
|
|
@@ -362,11 +363,48 @@ export function sha256(value) {
|
|
|
362
363
|
function stableId(prefix, ...parts) {
|
|
363
364
|
return `${prefix}_${createHash('sha256').update(parts.join('\0')).digest('hex')}`;
|
|
364
365
|
}
|
|
366
|
+
export const SessionRejectionDetailSchema = z.union([
|
|
367
|
+
z.object({ limit: z.string(), configured: z.number(), observed: z.number(),
|
|
368
|
+
setting: z.string().optional(), origin: z.enum(['flag', 'env', 'config', 'default']).optional() }),
|
|
369
|
+
z.object({ issues: z.array(z.object({ path: z.string(), code: z.string() })) }),
|
|
370
|
+
]);
|
|
371
|
+
export function schemaIssueDetail(path, code = 'custom') {
|
|
372
|
+
return { issues: [{ path, code }] };
|
|
373
|
+
}
|
|
374
|
+
export function assertSessionResourceLimit(limit, configured, observed) {
|
|
375
|
+
if (observed > configured) {
|
|
376
|
+
throw new SessionContractError('RESOURCE_LIMIT_EXCEEDED', 'session resource limit exceeded', {
|
|
377
|
+
limit, configured, observed,
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
/** Extract schema locations and validator codes without messages or input values. */
|
|
382
|
+
export function schemaRejectionDetail(error) {
|
|
383
|
+
const issues = [];
|
|
384
|
+
const visit = (entries) => {
|
|
385
|
+
for (const issue of entries) {
|
|
386
|
+
if (issues.length >= 20)
|
|
387
|
+
return;
|
|
388
|
+
if (issue.code === 'invalid_union') {
|
|
389
|
+
for (const branch of issue.unionErrors)
|
|
390
|
+
visit(branch.issues);
|
|
391
|
+
}
|
|
392
|
+
else {
|
|
393
|
+
issues.push({ path: issue.path.join('.') || '<root>', code: issue.code });
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
};
|
|
397
|
+
visit(error.issues);
|
|
398
|
+
return redactSessionValue({ issues }).value;
|
|
399
|
+
}
|
|
365
400
|
export class SessionContractError extends Error {
|
|
366
401
|
code;
|
|
367
|
-
|
|
368
|
-
|
|
402
|
+
detail;
|
|
403
|
+
constructor(code, message, detail) {
|
|
404
|
+
super(redactSessionText(message).text);
|
|
369
405
|
this.code = code;
|
|
406
|
+
this.detail = detail;
|
|
407
|
+
this.detail = redactSessionValue(detail).value;
|
|
370
408
|
this.name = 'SessionContractError';
|
|
371
409
|
}
|
|
372
410
|
}
|
|
@@ -114,7 +114,7 @@ export function reconcileCoveragePreflight(preflight, sources) {
|
|
|
114
114
|
return entry;
|
|
115
115
|
const selected = sources.filter((source) => source.provider === entry.provider);
|
|
116
116
|
const imported = selected.length === entry.sourceCount && selected.length > 0
|
|
117
|
-
&& selected.every((source) => accepted.has(source.status) && source.eventsAccepted > 0);
|
|
117
|
+
&& selected.every((source) => source.status === 'excluded' || (accepted.has(source.status) && source.eventsAccepted > 0));
|
|
118
118
|
return {
|
|
119
119
|
...entry,
|
|
120
120
|
disposition: !imported ? 'import-incomplete'
|
|
@@ -13,6 +13,7 @@ import { SessionContractError } from './contracts.js';
|
|
|
13
13
|
import { buildSessionAiwgFortemiIndexExport, SESSION_EXPORT_INDEX_SCHEMA_VERSION, } from './fortemi-export-mapping.js';
|
|
14
14
|
import { discoverSessionOutputCandidates } from './output-lineage.js';
|
|
15
15
|
import { FilesystemDerivedOutputIndex } from './output-registration.js';
|
|
16
|
+
import { redactSessionValue } from './policy.js';
|
|
16
17
|
export const SESSION_EXPORT_PLAN_SCHEMA_VERSION = '1.1.0';
|
|
17
18
|
function eventDigestSummary(events) {
|
|
18
19
|
const hash = createHash('sha256');
|
|
@@ -43,7 +44,7 @@ function localEventAttachment(event, projectRoot) {
|
|
|
43
44
|
&& value.dataBytes.every((item) => Number.isInteger(item) && Number(item) >= 0 && Number(item) <= 255)) {
|
|
44
45
|
return { filename, mediaType, bytes: Uint8Array.from(value.dataBytes) };
|
|
45
46
|
}
|
|
46
|
-
if (typeof value.dataUrl === 'string') {
|
|
47
|
+
if (typeof value.dataUrl === 'string' && !value.dataUrl.startsWith('[REDACTED:')) {
|
|
47
48
|
const match = /^data:([^;,]*)(;base64)?,(.*)$/s.exec(value.dataUrl);
|
|
48
49
|
if (!match)
|
|
49
50
|
throw new SessionContractError('MALFORMED_SOURCE', `invalid data URL attachment: ${event.eventId}`);
|
|
@@ -52,7 +53,7 @@ function localEventAttachment(event, projectRoot) {
|
|
|
52
53
|
: Buffer.from(decodeURIComponent(match[3]), 'utf8');
|
|
53
54
|
return { filename, mediaType: match[1] || mediaType, bytes };
|
|
54
55
|
}
|
|
55
|
-
if (typeof value.fileUrl === 'string') {
|
|
56
|
+
if (typeof value.fileUrl === 'string' && !value.fileUrl.startsWith('[REDACTED:')) {
|
|
56
57
|
if (!projectRoot)
|
|
57
58
|
throw new SessionContractError('SOURCE_NOT_AUTHORIZED', 'project root is required for file attachments');
|
|
58
59
|
const root = realpathSync(projectRoot);
|
|
@@ -157,7 +158,7 @@ export function buildSessionExportPlan(repository, options) {
|
|
|
157
158
|
sampleRecordIds: index.items.slice(0, sampleSize).map((item) => item.id),
|
|
158
159
|
},
|
|
159
160
|
};
|
|
160
|
-
return { plan, sessions, eventsBySessionId };
|
|
161
|
+
return { plan: redactSessionValue(plan).value, sessions, eventsBySessionId };
|
|
161
162
|
}
|
|
162
163
|
/**
|
|
163
164
|
* Re-selects the plan's sessions from the repository and compares digests
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { homedir } from 'node:os';
|
|
2
|
+
import { basename, dirname, extname, isAbsolute } from 'node:path';
|
|
3
|
+
import { SessionContractError } from './contracts.js';
|
|
4
|
+
import { grokbotConversationIdFromLocator } from './adapters/grokbot-locator.js';
|
|
5
|
+
export function validateImportExclusions(value) {
|
|
6
|
+
if (!Array.isArray(value) || !value.every(entry => typeof entry === 'string' && entry.trim().length > 0)) {
|
|
7
|
+
throw new SessionContractError('INVALID_ARGUMENT', 'sessions.import.exclude must be an array of non-empty strings');
|
|
8
|
+
}
|
|
9
|
+
for (const entry of value) {
|
|
10
|
+
if (!isAbsolute(entry) && entry !== '~' && !entry.startsWith('~/') && /[/*?\\~]/.test(entry)) {
|
|
11
|
+
throw new SessionContractError('INVALID_ARGUMENT', 'sessions.import.exclude path globs must be absolute or ~/ prefixed');
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export function resolveImportExclusions(config, flags = [], env = process.env) {
|
|
16
|
+
const configured = config?.exclude === undefined ? [] : config.exclude;
|
|
17
|
+
validateImportExclusions(configured);
|
|
18
|
+
const entries = [...configured, ...(env.AIWG_SESSIONS_IMPORT_EXCLUDE === undefined
|
|
19
|
+
? [] : env.AIWG_SESSIONS_IMPORT_EXCLUDE.split(',').map(entry => entry.trim())), ...flags];
|
|
20
|
+
validateImportExclusions(entries);
|
|
21
|
+
return [...new Set(entries)];
|
|
22
|
+
}
|
|
23
|
+
/** Use only discovery metadata and locator names; never inspect source content. */
|
|
24
|
+
export function matchImportExclusion(source, entries) {
|
|
25
|
+
const ids = [source.nativeSessionId, nativeSessionIdFromLocator(source)];
|
|
26
|
+
for (const entry of entries) {
|
|
27
|
+
if (isAbsolute(entry) || entry === '~' || entry.startsWith('~/')) {
|
|
28
|
+
const pattern = entry.startsWith('~') ? homedir() + entry.slice(1) : entry;
|
|
29
|
+
if (globExpression(pattern).test(source.locator))
|
|
30
|
+
return { entry, kind: 'path-glob' };
|
|
31
|
+
}
|
|
32
|
+
else if (ids.includes(entry))
|
|
33
|
+
return { entry, kind: 'session-id' };
|
|
34
|
+
}
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
export function nativeSessionIdFromLocator(source) {
|
|
38
|
+
if (source.provider === 'grokbot')
|
|
39
|
+
return grokbotConversationIdFromLocator(source.locator) ?? undefined;
|
|
40
|
+
if (source.provider === 'muse')
|
|
41
|
+
return basename(dirname(source.locator));
|
|
42
|
+
const name = basename(source.locator, extname(source.locator));
|
|
43
|
+
if (source.provider === 'codex' || source.provider === 'pi') {
|
|
44
|
+
return /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/i.exec(name)?.[1] ?? name;
|
|
45
|
+
}
|
|
46
|
+
return name;
|
|
47
|
+
}
|
|
48
|
+
function globExpression(pattern) {
|
|
49
|
+
let expression = '^';
|
|
50
|
+
for (let index = 0; index < pattern.length; index++) {
|
|
51
|
+
const character = pattern[index];
|
|
52
|
+
if (character === '*') {
|
|
53
|
+
if (pattern[index + 1] === '*') {
|
|
54
|
+
index++;
|
|
55
|
+
if (pattern[index + 1] === '/') {
|
|
56
|
+
expression += '(?:.*/)?';
|
|
57
|
+
index++;
|
|
58
|
+
}
|
|
59
|
+
else
|
|
60
|
+
expression += '.*';
|
|
61
|
+
}
|
|
62
|
+
else
|
|
63
|
+
expression += '[^/]*';
|
|
64
|
+
}
|
|
65
|
+
else if (character === '?')
|
|
66
|
+
expression += '[^/]';
|
|
67
|
+
else
|
|
68
|
+
expression += character.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
69
|
+
}
|
|
70
|
+
return new RegExp(expression + '$');
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=import-exclusions.js.map
|