Skip to content

Commit d2a50ca

Browse files
committed
feat(extensions): add host-owned external integration policy
1 parent 1691f38 commit d2a50ca

62 files changed

Lines changed: 9728 additions & 702 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

scripts/core-boundaries/rules/feature-rules.mjs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,12 @@ export const productCoreFeatureAssemblyRules = [
127127
requiredFeatures: ['product-full'],
128128
reason: 'CLI must explicitly assemble the full bitfun-core product runtime',
129129
},
130+
{
131+
manifestPath: 'src/apps/server/Cargo.toml',
132+
dependencyName: 'bitfun-core',
133+
requiredFeatures: ['product-full'],
134+
reason: 'Server must explicitly assemble the full bitfun-core product runtime',
135+
},
130136
{
131137
manifestPath: 'src/crates/interfaces/acp/Cargo.toml',
132138
dependencyName: 'bitfun-core',

scripts/core-boundaries/rules/source/public-api-rules.mjs

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export const publicApiContractSlices = [
99
'external-source-tool-contract',
1010
'external-source-subagent-contract',
1111
'external-source-mcp-contract',
12+
'external-integration-policy-contract',
1213
];
1314

1415
const contractSlices = {
@@ -20,6 +21,7 @@ const contractSlices = {
2021
externalSourceToolContract: 'external-source-tool-contract',
2122
externalSourceSubagentContract: 'external-source-subagent-contract',
2223
externalSourceMcpContract: 'external-source-mcp-contract',
24+
externalIntegrationPolicyContract: 'external-integration-policy-contract',
2325
};
2426

2527
function pluginRuntimeEntry(symbol, p0, consumer, verification, contractSlice, wireImpact = true) {
@@ -230,6 +232,55 @@ function externalSourceEntry(symbol, owner, consumer, wireImpact = false) {
230232
};
231233
}
232234

235+
function externalIntegrationPolicyEntry(
236+
symbol,
237+
owner = 'product-domains external integration policy contract owner',
238+
consumer = 'bitfun-core product composition and cross-host product surfaces',
239+
wireImpact = true,
240+
) {
241+
return {
242+
symbol,
243+
owner,
244+
consumer,
245+
verification:
246+
'external integration policy contract tests, core policy lifecycle tests, cross-host route tests, and Web policy-control tests',
247+
p0: 'host-owned external integration policy and OpenCode-compatible product defaults',
248+
contractSlice: contractSlices.externalIntegrationPolicyContract,
249+
wireImpact,
250+
rationale:
251+
'all product surfaces need one ecosystem-neutral, versioned, fail-closed policy contract while concrete ecosystem defaults remain in product assembly',
252+
exit:
253+
'remove only through a reviewed policy-contract migration with equivalent compatibility, safety-ceiling, and cross-host behavior tests',
254+
};
255+
}
256+
257+
export const externalIntegrationPolicyPublicApiEntries = [
258+
'EXTERNAL_INTEGRATION_POLICY_SCHEMA_MAJOR',
259+
'ExternalIntegrationMode',
260+
'ExternalIntegrationAccess',
261+
'ExternalEcosystemPolicy',
262+
'ExternalIntegrationPolicySettings',
263+
'ExternalIntegrationPolicySettingsView',
264+
'ExternalEcosystemPolicyOverride',
265+
'ExternalEcosystemPolicyOverrideView',
266+
'ExternalIntegrationPolicyOverride',
267+
'ExternalIntegrationPolicyOverrideView',
268+
'ExternalIntegrationPolicyDocument',
269+
'ExternalIntegrationCapabilityDescriptor',
270+
'ExternalIntegrationEcosystemDescriptor',
271+
'ExternalEcosystemPolicyView',
272+
'EffectiveExternalEcosystemPolicy',
273+
'EffectiveExternalIntegrationPolicy',
274+
'ExternalIntegrationPolicyStatus',
275+
'ExternalIntegrationPolicySnapshot',
276+
'ExternalIntegrationPolicyScope',
277+
'ExternalIntegrationPolicyOperation',
278+
'ExternalIntegrationPolicyMutation',
279+
'evaluate_external_integration_policy',
280+
'external_integration_policy_snapshot',
281+
'incompatible_external_integration_policy_snapshot',
282+
].map((symbol) => externalIntegrationPolicyEntry(symbol));
283+
233284
function externalToolEntry(symbol, owner, consumer, wireImpact = false) {
234285
return {
235286
symbol,
@@ -298,6 +349,9 @@ export const externalSourceContractPublicApiEntries = [
298349
'ExternalSourceContext',
299350
'ExternalWatchRoot',
300351
'ExternalSourceProviderError',
352+
'ExternalSourceOperationErrorCode',
353+
'ExternalSourceOperationError',
354+
'ExternalSourceOperationResult',
301355
'PromptCommandSourceProvider',
302356
'ExternalSourceLifecycleState',
303357
'ExternalSourceCatalogEntry',
@@ -306,6 +360,10 @@ export const externalSourceContractPublicApiEntries = [
306360
'PromptCommandConflict',
307361
'prompt_command_conflict_key',
308362
'ExternalSourceCatalogSnapshot',
363+
'ExternalPromptCommandDefinitionSummary',
364+
'ExternalPromptCommandSummary',
365+
'ExternalSourcePublicSnapshot',
366+
'ExternalSourceHostCapabilities',
309367
].map((symbol) =>
310368
externalSourceEntry(
311369
symbol,
@@ -459,6 +517,30 @@ export const externalSourceCoordinatorPublicApiEntries = [
459517
];
460518

461519
export const externalSourceCorePublicApiEntries = [
520+
...[
521+
'ExternalIntegrationAccess',
522+
'ExternalIntegrationMode',
523+
'ExternalIntegrationPolicyMutation',
524+
'ExternalIntegrationPolicyOperation',
525+
'ExternalIntegrationPolicyScope',
526+
'EffectiveExternalIntegrationPolicy',
527+
'ExternalIntegrationPolicySnapshot',
528+
'ExternalIntegrationPolicyStatus',
529+
'EcosystemId',
530+
'ExternalIntegrationCapabilityId',
531+
'EXTERNAL_CAPABILITY_COMMAND',
532+
'EXTERNAL_CAPABILITY_TOOL',
533+
'EXTERNAL_CAPABILITY_SUBAGENT',
534+
'EXTERNAL_CAPABILITY_MCP',
535+
'update_external_integration_policy',
536+
].map((symbol) =>
537+
externalIntegrationPolicyEntry(
538+
symbol,
539+
'bitfun-core external integration policy composition facade',
540+
'bitfun-cli, Desktop, Server, Peer Host, and Web API adapters',
541+
true,
542+
),
543+
),
462544
...[
463545
'ExpandedPromptCommand',
464546
'ExternalSourceCatalogEntry',
@@ -467,6 +549,10 @@ export const externalSourceCorePublicApiEntries = [
467549
'ExternalSourceDiagnostic',
468550
'ExternalSourceDiagnosticSeverity',
469551
'ExternalSourceLifecycleState',
552+
'ExternalSourceHostCapabilities',
553+
'ExternalSourceOperationError',
554+
'ExternalSourceOperationErrorCode',
555+
'ExternalSourceOperationResult',
470556
'PromptCommandAvailability',
471557
'PromptCommandCatalogEntry',
472558
'PromptCommandDefinition',
@@ -476,10 +562,13 @@ export const externalSourceCorePublicApiEntries = [
476562
'remember_external_source_conflict_choice',
477563
'set_external_prompt_command_conflict_choice',
478564
'external_source_snapshot',
565+
'external_source_read_only_snapshot',
479566
'set_external_source_enabled',
480567
'expand_external_prompt_command',
568+
'sanitize_external_source_operation_error',
481569
'subscribe_external_source_updates',
482570
'ExternalSourceSubscription',
571+
'ExternalSourcePublicSnapshot',
483572
].map((symbol) =>
484573
externalSourceEntry(
485574
symbol,
@@ -493,6 +582,7 @@ export const externalSourceCorePublicApiEntries = [
493582
'ExternalToolCapability',
494583
'ExternalToolCatalogEntry',
495584
'ExternalToolConflict',
585+
'ExternalToolConflictCandidateKind',
496586
'ExternalToolRuntimeKind',
497587
'set_external_tool_target_decision',
498588
'set_external_tool_conflict_choice',
@@ -657,6 +747,12 @@ export const publicApiAllowlistRules = [
657747
'managed plugin package and trust contracts must stay explicitly budgeted and ecosystem-neutral',
658748
allowedSymbolEntries: pluginSourceContractPublicApiEntries,
659749
},
750+
{
751+
path: 'src/crates/contracts/product-domains/src/external_integration_policy.rs',
752+
reason:
753+
'external integration policy contracts must stay ecosystem-neutral, versioned, fail-closed, and explicitly consumer-backed',
754+
allowedSymbolEntries: externalIntegrationPolicyPublicApiEntries,
755+
},
660756
{
661757
path: 'src/crates/contracts/product-domains/src/external_sources.rs',
662758
reason:

scripts/core-boundaries/self-test.mjs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ export function runManifestParserSelfTest({
165165
for (const manifestPath of [
166166
'src/apps/desktop/Cargo.toml',
167167
'src/apps/cli/Cargo.toml',
168+
'src/apps/server/Cargo.toml',
168169
'src/crates/interfaces/acp/Cargo.toml',
169170
]) {
170171
if (!productCoreRulePaths.has(manifestPath)) {
@@ -195,15 +196,21 @@ export function runManifestParserSelfTest({
195196
},
196197
{
197198
manifestPath: 'src/apps/server/Cargo.toml',
198-
text: '[dependencies]\naxum = { workspace = true }',
199+
text:
200+
'[dependencies]\nbitfun-core = { path = "../../crates/assembly/core", default-features = false, features = ["product-full"] }',
199201
},
200202
{
201203
manifestPath: 'src/crates/interfaces/acp/Cargo.toml',
202204
text: '[dependencies."bitfun-core"]\npath = "../../assembly/core"\ndefault-features = false\nfeatures = ["product-full"]',
203205
},
204206
]);
205-
if (discoveredProductCoreManifests.join(',') !== 'src/apps/desktop/Cargo.toml,src/crates/interfaces/acp/Cargo.toml') {
206-
throw new Error('product core dependency scanner must discover only manifests that depend on bitfun-core');
207+
if (
208+
discoveredProductCoreManifests.join(',') !==
209+
'src/apps/desktop/Cargo.toml,src/apps/server/Cargo.toml,src/crates/interfaces/acp/Cargo.toml'
210+
) {
211+
throw new Error(
212+
'product core dependency scanner must discover only manifests that depend on bitfun-core',
213+
);
207214
}
208215
const ownerFeatureRulePaths = new Set(
209216
ownerCrateFeatureAssemblyRules.map((rule) => rule.manifestPath),

0 commit comments

Comments
 (0)