@adhdev/daemon-core 1.0.18-rc.16 → 1.0.18-rc.18
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/dist/commands/cli-manager.d.ts +9 -0
- package/dist/config/mesh-json-config.d.ts +62 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +919 -421
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +880 -391
- package/dist/index.mjs.map +1 -1
- package/dist/providers/auto-approve-modes.d.ts +14 -0
- package/dist/providers/cli-provider-instance.d.ts +4 -0
- package/dist/providers/contracts.d.ts +17 -0
- package/dist/providers/provider-schema.d.ts +1 -0
- package/dist/repo-mesh-types.d.ts +38 -6
- package/dist/shared-types.d.ts +3 -1
- package/package.json +3 -3
- package/src/commands/cli-manager.ts +54 -8
- package/src/commands/med-family/mesh-crud.ts +155 -0
- package/src/config/mesh-json-config.ts +103 -0
- package/src/index.ts +21 -1
- package/src/mesh/mesh-event-forwarding.ts +18 -2
- package/src/mesh/mesh-queue-assignment.ts +66 -9
- package/src/providers/auto-approve-modes.ts +97 -0
- package/src/providers/cli-provider-instance.ts +45 -13
- package/src/providers/contracts.ts +25 -1
- package/src/providers/provider-schema.ts +83 -0
- package/src/providers/sdk/v1/schemas/cli/provider.schema.json +44 -0
- package/src/repo-mesh-types.ts +112 -12
- package/src/shared-types.ts +3 -1
- package/src/status/snapshot.ts +2 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AutoApproveMode, AutoApproveModeRisk, AutoApproveModeStrategy, ProviderModule } from './contracts.js';
|
|
2
|
+
export interface ResolvedAutoApproveMode {
|
|
3
|
+
active: boolean;
|
|
4
|
+
strategy: AutoApproveModeStrategy;
|
|
5
|
+
modeId: string;
|
|
6
|
+
}
|
|
7
|
+
/** Runtime defense-in-depth for provider definitions that bypass schema validation. */
|
|
8
|
+
export declare function deriveAutoApproveModeRisk(mode: Pick<AutoApproveMode, 'risk' | 'launchArgs'>): AutoApproveModeRisk;
|
|
9
|
+
/**
|
|
10
|
+
* Resolve new mode settings before the legacy boolean. A stale/unknown explicit
|
|
11
|
+
* mode id fails closed instead of falling through to an enabled legacy setting.
|
|
12
|
+
*/
|
|
13
|
+
export declare function resolveProviderAutoApproveMode(provider: ProviderModule, settings: Record<string, unknown> | undefined): ResolvedAutoApproveMode;
|
|
14
|
+
export declare function findProviderAutoApproveMode(provider: ProviderModule | undefined, modeId: string): AutoApproveMode | undefined;
|
|
@@ -810,7 +810,11 @@ export declare class CliProviderInstance implements ProviderInstance {
|
|
|
810
810
|
getAdapter(): ProviderCliAdapter;
|
|
811
811
|
get cliType(): string;
|
|
812
812
|
get cliName(): string;
|
|
813
|
+
private resolveAutoApproveMode;
|
|
814
|
+
/** Legacy boolean view retained for internal/test compatibility. */
|
|
813
815
|
private shouldAutoApprove;
|
|
816
|
+
private shouldUsePtyAutoApprove;
|
|
817
|
+
private resetPtyAutoApproveState;
|
|
814
818
|
/** @see ProviderInstance.noteManualInteraction */
|
|
815
819
|
noteManualInteraction(now?: number, opts?: {
|
|
816
820
|
passive?: boolean;
|
|
@@ -389,6 +389,21 @@ export interface ProviderCompatibilityEntry {
|
|
|
389
389
|
ideVersion: string;
|
|
390
390
|
scriptDir: string;
|
|
391
391
|
}
|
|
392
|
+
export type AutoApproveModeStrategy = 'pty-parse-default' | 'launch-args' | 'post-boot-command';
|
|
393
|
+
export type AutoApproveModeRisk = 'safe' | 'caution' | 'dangerous';
|
|
394
|
+
export interface AutoApproveMode {
|
|
395
|
+
id: string;
|
|
396
|
+
label: string;
|
|
397
|
+
strategy: AutoApproveModeStrategy;
|
|
398
|
+
risk: AutoApproveModeRisk;
|
|
399
|
+
warning?: string;
|
|
400
|
+
launchArgs?: string[];
|
|
401
|
+
removeArgs?: string[];
|
|
402
|
+
}
|
|
403
|
+
export interface AutoApproveModesConfig {
|
|
404
|
+
default: string;
|
|
405
|
+
modes: AutoApproveMode[];
|
|
406
|
+
}
|
|
392
407
|
export interface ProviderModule {
|
|
393
408
|
/** Unique identifier (e.g. 'cline', 'cursor', 'gemini-cli') */
|
|
394
409
|
type: string;
|
|
@@ -418,6 +433,8 @@ export interface ProviderModule {
|
|
|
418
433
|
status?: string;
|
|
419
434
|
/** Inventory/support detail string maintained in adhdev-providers */
|
|
420
435
|
details?: string;
|
|
436
|
+
/** Provider-specific auto-approve choices and their launch/runtime strategy. */
|
|
437
|
+
autoApproveModes?: AutoApproveModesConfig;
|
|
421
438
|
/** Install instructions (shown when command is missing) */
|
|
422
439
|
install?: string;
|
|
423
440
|
/** Custom version detection command (e.g. 'cursor --version', 'claude -v') */
|
|
@@ -14,6 +14,8 @@ import type { GitRepoStatus, GitCompactSummary } from './git/git-types.js';
|
|
|
14
14
|
import type { MeshMissionSummary, MeshMissionSlimSummary } from './mesh/mesh-missions.js';
|
|
15
15
|
import type { MeshMagiActivitySummary } from './mesh/mesh-magi-status.js';
|
|
16
16
|
import type { MagiKindPanelMap, DifficultyBrainMap, NodeCapabilitySlot } from '@adhdev/mesh-shared';
|
|
17
|
+
import type { ProviderModule } from './providers/contracts.js';
|
|
18
|
+
import type { RepoMeshDeclarativeConfig } from './config/mesh-json-config.js';
|
|
17
19
|
export interface RepoMesh {
|
|
18
20
|
id: string;
|
|
19
21
|
name: string;
|
|
@@ -255,6 +257,8 @@ export interface RepoMeshPolicy {
|
|
|
255
257
|
* A node policy may override this per-node (RepoMeshNodePolicy.delegatedWorkerAutoApprove).
|
|
256
258
|
*/
|
|
257
259
|
delegatedWorkerAutoApprove?: boolean;
|
|
260
|
+
/** Explicit opt-in required before delegated workers may use a dangerous provider mode. */
|
|
261
|
+
delegatedWorkerDangerousModeAllow?: boolean;
|
|
258
262
|
/**
|
|
259
263
|
* MESH-SEND-KEYS (feature 3): opt-in to allow the coordinator to inject
|
|
260
264
|
* DESTRUCTIVE keys (CTRL_C / ESC) into a worker PTY via mesh_send_keys. These
|
|
@@ -406,6 +410,8 @@ export interface RepoMeshNodePolicy {
|
|
|
406
410
|
* precedence over the mesh-level policy for worker sessions launched onto this node.
|
|
407
411
|
*/
|
|
408
412
|
delegatedWorkerAutoApprove?: boolean;
|
|
413
|
+
/** Per-node override for dangerous delegated worker mode authorization. */
|
|
414
|
+
delegatedWorkerDangerousModeAllow?: boolean;
|
|
409
415
|
/**
|
|
410
416
|
* MESH-SEND-KEYS (feature 3): per-node override for
|
|
411
417
|
* RepoMeshPolicy.allowSendKeysDestructive.
|
|
@@ -524,13 +530,39 @@ export declare function normalizeAutoFastForwardPolicy(value: unknown): NonNulla
|
|
|
524
530
|
*/
|
|
525
531
|
export declare function mergeAndNormalizePolicy(base: RepoMeshPolicy | undefined, patch: Partial<RepoMeshPolicy> | undefined): RepoMeshPolicy;
|
|
526
532
|
/**
|
|
527
|
-
* Resolve
|
|
528
|
-
*
|
|
529
|
-
*
|
|
530
|
-
*
|
|
531
|
-
*
|
|
533
|
+
* Resolve delegated worker auto-approve. Legacy providers return a boolean. Providers
|
|
534
|
+
* with modes return a mode id, except a dangerous mode is downgraded to a
|
|
535
|
+
* non-dangerous PTY mode unless mesh/node policy explicitly opts in.
|
|
536
|
+
*
|
|
537
|
+
* THREE EXPLICIT STAGES — do not collapse them; the ordering is a hard MAGI
|
|
538
|
+
* invariant:
|
|
539
|
+
*
|
|
540
|
+
* ① ENABLE gate (machine-local policy only): node boolean > mesh boolean.
|
|
541
|
+
* `enabled=false` returns `false` IMMEDIATELY, BEFORE any mode selection.
|
|
542
|
+
* The repo `mesh.json` providerDefaults has ZERO influence here — a
|
|
543
|
+
* node/mesh opt-out is never overridden by a repo-declared requested mode.
|
|
544
|
+
*
|
|
545
|
+
* ② MODE selection (only when enabled === true):
|
|
546
|
+
* task override [FUTURE — param reserved below, not yet wired] >
|
|
547
|
+
* repo mesh.json providerDefaults.autoApproveModes[providerType] >
|
|
548
|
+
* provider spec autoApproveModes.default.
|
|
549
|
+
* A repo-requested mode ID is adopted ONLY when it exists in the provider's
|
|
550
|
+
* own `autoApproveModes.modes`; an unknown/stale/typo'd ID is IGNORED and we
|
|
551
|
+
* fall back to the provider default (fail-closed: never coerce into a
|
|
552
|
+
* dangerous mode via a bad ID).
|
|
553
|
+
*
|
|
554
|
+
* ③ DANGEROUS gate: whichever mode stage ② picked, if it is dangerous and the
|
|
555
|
+
* machine-local delegatedWorkerDangerousModeAllow is not set, downgrade to a
|
|
556
|
+
* non-dangerous PTY-parse mode (or `false` if none exists).
|
|
532
557
|
*/
|
|
533
|
-
export declare function resolveDelegatedWorkerAutoApprove(meshPolicy?: Pick<RepoMeshPolicy, 'delegatedWorkerAutoApprove'> | null, nodePolicy?: Pick<RepoMeshNodePolicy, 'delegatedWorkerAutoApprove'> | null): boolean;
|
|
558
|
+
export declare function resolveDelegatedWorkerAutoApprove(meshPolicy?: Pick<RepoMeshPolicy, 'delegatedWorkerAutoApprove' | 'delegatedWorkerDangerousModeAllow'> | null, nodePolicy?: Pick<RepoMeshNodePolicy, 'delegatedWorkerAutoApprove' | 'delegatedWorkerDangerousModeAllow'> | null, provider?: Pick<ProviderModule, 'autoApproveModes'> | null, repoConfig?: RepoMeshDeclarativeConfig | null, providerType?: string | null): boolean | string;
|
|
559
|
+
export declare function resolveDelegatedWorkerDangerousModeAllow(meshPolicy?: Pick<RepoMeshPolicy, 'delegatedWorkerDangerousModeAllow'> | null, nodePolicy?: Pick<RepoMeshNodePolicy, 'delegatedWorkerDangerousModeAllow'> | null): boolean;
|
|
560
|
+
/** Shape a boolean-or-mode resolution for the settings precedence contract. */
|
|
561
|
+
export declare function delegatedWorkerAutoApproveSettings(meshPolicy?: Pick<RepoMeshPolicy, 'delegatedWorkerAutoApprove' | 'delegatedWorkerDangerousModeAllow'> | null, nodePolicy?: Pick<RepoMeshNodePolicy, 'delegatedWorkerAutoApprove' | 'delegatedWorkerDangerousModeAllow'> | null, provider?: Pick<ProviderModule, 'autoApproveModes'> | null, repoConfig?: RepoMeshDeclarativeConfig | null, providerType?: string | null): {
|
|
562
|
+
autoApprove: boolean | undefined;
|
|
563
|
+
autoApproveMode: string | undefined;
|
|
564
|
+
delegatedWorkerDangerousModeAllow: boolean;
|
|
565
|
+
};
|
|
534
566
|
/**
|
|
535
567
|
* MESH-SEND-KEYS (feature 3): resolve whether DESTRUCTIVE key injection
|
|
536
568
|
* (CTRL_C/ESC via mesh_send_keys) is permitted for a node. Node policy overrides
|
package/dist/shared-types.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ export type { ProviderState, ProviderStatus, ActiveChatData, IdeProviderState, C
|
|
|
13
13
|
export type { ProviderErrorReason } from './providers/provider-instance.js';
|
|
14
14
|
import type { ActiveChatData as _ActiveChatData, ProviderErrorReason as _ProviderErrorReason } from './providers/provider-instance.js';
|
|
15
15
|
import type { WorkspaceEntry } from './config/workspaces.js';
|
|
16
|
-
import type { ProviderMeshCoordinatorConfig, ProviderResumeCapability } from './providers/contracts.js';
|
|
16
|
+
import type { AutoApproveModesConfig, ProviderMeshCoordinatorConfig, ProviderResumeCapability } from './providers/contracts.js';
|
|
17
17
|
import type { GitCompactSummary, GitWorkspaceUpdate, WorkspaceGitSubscriptionParams } from './git/git-types.js';
|
|
18
18
|
import type { InteractivePrompt } from './providers/types/interactive-prompt.js';
|
|
19
19
|
export type { GitCommandName, GitCompactSummary, GitDiffSummary, GitFailureReason, GitFileChange, GitFileChangeStatus, GitRepoIdentity, GitRepoStatus, GitSnapshot, GitSnapshotCompareSummary, GitSnapshotReason, GitWorkspaceUpdate, WorkspaceGitSubscriptionParams, } from './git/git-types.js';
|
|
@@ -428,6 +428,8 @@ export interface AvailableProviderInfo {
|
|
|
428
428
|
lastVerification?: MachineProviderCheckResult;
|
|
429
429
|
/** Provider-declared Repo Mesh coordinator/MCP behavior. */
|
|
430
430
|
meshCoordinator?: ProviderMeshCoordinatorConfig;
|
|
431
|
+
/** Provider-declared auto-approve choices shown by session launch UIs. */
|
|
432
|
+
autoApproveModes?: AutoApproveModesConfig;
|
|
431
433
|
/** BRAIN-ROUTING: suggested model values for the new-session model dropdown. */
|
|
432
434
|
modelOptions?: string[];
|
|
433
435
|
/** BRAIN-ROUTING: reasoning-effort values for the new-session thinking dropdown. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adhdev/daemon-core",
|
|
3
|
-
"version": "1.0.18-rc.
|
|
3
|
+
"version": "1.0.18-rc.18",
|
|
4
4
|
"description": "ADHDev daemon core — CDP, IDE detection, providers, command execution",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
"author": "vilmire",
|
|
48
48
|
"license": "AGPL-3.0-or-later",
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@adhdev/mesh-shared": "1.0.18-rc.
|
|
51
|
-
"@adhdev/session-host-core": "1.0.18-rc.
|
|
50
|
+
"@adhdev/mesh-shared": "1.0.18-rc.18",
|
|
51
|
+
"@adhdev/session-host-core": "1.0.18-rc.18",
|
|
52
52
|
"@agentclientprotocol/sdk": "^0.16.1",
|
|
53
53
|
"ajv": "^8.20.0",
|
|
54
54
|
"ajv-formats": "^3.0.1",
|
|
@@ -34,6 +34,7 @@ import type { SessionRegistry } from '../sessions/registry.js';
|
|
|
34
34
|
import type { ProviderInstance } from '../providers/provider-instance.js';
|
|
35
35
|
import { LOG } from '../logging/logger.js';
|
|
36
36
|
import { shouldRestoreHostedRuntime } from './hosted-runtime-restore.js';
|
|
37
|
+
import { findProviderAutoApproveMode, resolveProviderAutoApproveMode } from '../providers/auto-approve-modes.js';
|
|
37
38
|
|
|
38
39
|
// ─── external dependency interface ──────────────────────────
|
|
39
40
|
|
|
@@ -452,6 +453,40 @@ export function expandThinkingLaunchArgs(
|
|
|
452
453
|
return template.map((part) => part.includes('{{level}}') ? part.replace('{{level}}', mapped) : part);
|
|
453
454
|
}
|
|
454
455
|
|
|
456
|
+
function matchesRemovedLaunchArg(arg: string, removeArg: string): boolean {
|
|
457
|
+
return arg === removeArg || (removeArg.startsWith('--') && arg.startsWith(`${removeArg}=`));
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* Apply a selected launch-args auto-approve mode without mutating provider metadata.
|
|
462
|
+
* removeArgs only targets provider-owned base spawn.args; launchArgs are prepended to
|
|
463
|
+
* per-launch args beside model/thinking args, making conflict removal order-independent.
|
|
464
|
+
*/
|
|
465
|
+
export function applyAutoApproveModeLaunchArgs(
|
|
466
|
+
provider: ProviderModule | undefined,
|
|
467
|
+
cliArgs: string[] | undefined,
|
|
468
|
+
settings: Record<string, unknown> | undefined,
|
|
469
|
+
): { provider: ProviderModule | undefined; cliArgs: string[] | undefined } {
|
|
470
|
+
if (!provider) return { provider, cliArgs };
|
|
471
|
+
const resolved = resolveProviderAutoApproveMode(provider, settings);
|
|
472
|
+
if (!resolved.active || resolved.strategy !== 'launch-args') return { provider, cliArgs };
|
|
473
|
+
const mode = findProviderAutoApproveMode(provider, resolved.modeId);
|
|
474
|
+
if (!mode || !Array.isArray(mode.launchArgs) || mode.launchArgs.length === 0) return { provider, cliArgs };
|
|
475
|
+
|
|
476
|
+
const removeArgs = Array.isArray(mode.removeArgs) ? mode.removeArgs : [];
|
|
477
|
+
const baseArgs = provider.spawn?.args;
|
|
478
|
+
const filteredBaseArgs = Array.isArray(baseArgs) && removeArgs.length > 0
|
|
479
|
+
? baseArgs.filter((arg) => !removeArgs.some((removeArg) => matchesRemovedLaunchArg(arg, removeArg)))
|
|
480
|
+
: baseArgs;
|
|
481
|
+
const launchProvider = filteredBaseArgs === baseArgs
|
|
482
|
+
? provider
|
|
483
|
+
: { ...provider, spawn: { ...provider.spawn!, args: filteredBaseArgs } };
|
|
484
|
+
return {
|
|
485
|
+
provider: launchProvider,
|
|
486
|
+
cliArgs: [...mode.launchArgs, ...(cliArgs || [])],
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
|
|
455
490
|
function readSubcommandSessionId(args: string[], subcommands: string[]): string | undefined {
|
|
456
491
|
const resumeIndex = args.findIndex((arg) => subcommands.includes(arg));
|
|
457
492
|
if (resumeIndex < 0) return undefined;
|
|
@@ -1048,6 +1083,17 @@ export class DaemonCliManager {
|
|
|
1048
1083
|
console.log(colorize('cyan', ` 📦 Using provider: ${provider.name} (${provider.type})`));
|
|
1049
1084
|
}
|
|
1050
1085
|
|
|
1086
|
+
const launchSettings = {
|
|
1087
|
+
...this.providerLoader.getSettings(normalizedType),
|
|
1088
|
+
...(options?.settingsOverride || {}),
|
|
1089
|
+
};
|
|
1090
|
+
const versionResolvedProvider = provider
|
|
1091
|
+
? (this.providerLoader.resolve(cliType, { version: cliInfo.version }) || provider)
|
|
1092
|
+
: undefined;
|
|
1093
|
+
const autoApproveLaunch = applyAutoApproveModeLaunchArgs(versionResolvedProvider, cliArgs, launchSettings);
|
|
1094
|
+
const launchProvider = autoApproveLaunch.provider || provider;
|
|
1095
|
+
const cliArgsWithAutoApprove = autoApproveLaunch.cliArgs;
|
|
1096
|
+
|
|
1051
1097
|
// ─── Model axis (MAGI kind-panel): expand initialModel → launch args ───
|
|
1052
1098
|
// For a plain CLI provider the model is selected at spawn time via the manifest's
|
|
1053
1099
|
// modelLaunchArgs template ('{{model}}' → the requested model). ACP providers took
|
|
@@ -1055,10 +1101,10 @@ export class DaemonCliManager {
|
|
|
1055
1101
|
// or no requested model, is a no-op — model selection is best-effort and must never
|
|
1056
1102
|
// fail a launch. The model args are prepended so a caller's explicit cliArgs (e.g. a
|
|
1057
1103
|
// resume flag) still win positionally where order matters.
|
|
1058
|
-
const modelLaunchArgs = expandModelLaunchArgs(
|
|
1104
|
+
const modelLaunchArgs = expandModelLaunchArgs(launchProvider?.modelLaunchArgs, initialModel);
|
|
1059
1105
|
const cliArgsWithModel = modelLaunchArgs
|
|
1060
|
-
? [...modelLaunchArgs, ...(
|
|
1061
|
-
:
|
|
1106
|
+
? [...modelLaunchArgs, ...(cliArgsWithAutoApprove || [])]
|
|
1107
|
+
: cliArgsWithAutoApprove;
|
|
1062
1108
|
if (initialModel && !modelLaunchArgs) {
|
|
1063
1109
|
LOG.warn('CLI', `[${normalizedType}] initialModel='${initialModel}' requested but provider declares no modelLaunchArgs template — launching without model selection.`);
|
|
1064
1110
|
}
|
|
@@ -1069,7 +1115,7 @@ export class DaemonCliManager {
|
|
|
1069
1115
|
// Best-effort; a provider with no template (or no requested level) is a no-op. ACP
|
|
1070
1116
|
// providers route thinking through setConfigOption('thought_level') above.
|
|
1071
1117
|
const initialThinkingLevel = options?.initialThinkingLevel;
|
|
1072
|
-
const thinkingLaunchArgs = expandThinkingLaunchArgs(
|
|
1118
|
+
const thinkingLaunchArgs = expandThinkingLaunchArgs(launchProvider?.thinkingLaunchArgs, initialThinkingLevel, launchProvider?.thinkingLevelMap);
|
|
1073
1119
|
const cliArgsWithBrain = thinkingLaunchArgs
|
|
1074
1120
|
? [...thinkingLaunchArgs, ...(cliArgsWithModel || [])]
|
|
1075
1121
|
: cliArgsWithModel;
|
|
@@ -1078,13 +1124,13 @@ export class DaemonCliManager {
|
|
|
1078
1124
|
}
|
|
1079
1125
|
|
|
1080
1126
|
// ─── Resolve launch options → provider session binding ───
|
|
1081
|
-
const sessionBinding = resolveCliSessionBinding(
|
|
1127
|
+
const sessionBinding = resolveCliSessionBinding(launchProvider, normalizedType, cliArgsWithBrain, options?.resumeSessionId);
|
|
1082
1128
|
const resolvedCliArgs = sessionBinding.cliArgs;
|
|
1083
1129
|
|
|
1084
1130
|
// If InstanceManager exists, manage as CliProviderInstance unified
|
|
1085
1131
|
const instanceManager = this.deps.getInstanceManager();
|
|
1086
|
-
if (
|
|
1087
|
-
const resolvedProvider =
|
|
1132
|
+
if (launchProvider && instanceManager) {
|
|
1133
|
+
const resolvedProvider = launchProvider;
|
|
1088
1134
|
await this.registerCliInstance(
|
|
1089
1135
|
key,
|
|
1090
1136
|
normalizedType,
|
|
@@ -1092,7 +1138,7 @@ export class DaemonCliManager {
|
|
|
1092
1138
|
resolvedDir,
|
|
1093
1139
|
resolvedCliArgs,
|
|
1094
1140
|
resolvedProvider,
|
|
1095
|
-
|
|
1141
|
+
launchSettings,
|
|
1096
1142
|
false,
|
|
1097
1143
|
{
|
|
1098
1144
|
providerSessionId: sessionBinding.providerSessionId,
|
|
@@ -399,6 +399,161 @@ export const meshCrudHandlers: Record<string, MedFamilyHandler> = {
|
|
|
399
399
|
}
|
|
400
400
|
},
|
|
401
401
|
|
|
402
|
+
// READ path for `.adhdev/mesh.json` — returns the currently-committed repo
|
|
403
|
+
// config (parsed + normalized) for a workspace so a UI can render/edit the
|
|
404
|
+
// existing declarative zones (notably `providerDefaults.autoApproveModes`)
|
|
405
|
+
// WITHOUT re-deriving them from the machine-local scaffold. Never writes.
|
|
406
|
+
// `config` is undefined when no repo file exists (sourceType 'unavailable') or
|
|
407
|
+
// it is unparseable (sourceType 'invalid', with the parse error surfaced).
|
|
408
|
+
read_mesh_json_config: async (_ctx: MedFamilyContext, args: any) => {
|
|
409
|
+
const workspace = typeof args?.workspace === 'string' && args.workspace.trim() ? args.workspace.trim() : process.cwd();
|
|
410
|
+
try {
|
|
411
|
+
const { loadRepoMeshJsonConfig } = await import('../../config/mesh-json-config.js');
|
|
412
|
+
const loaded = loadRepoMeshJsonConfig(workspace);
|
|
413
|
+
return {
|
|
414
|
+
success: true,
|
|
415
|
+
workspace,
|
|
416
|
+
sourceType: loaded.sourceType,
|
|
417
|
+
source: loaded.source,
|
|
418
|
+
...(loaded.path ? { path: loaded.path } : {}),
|
|
419
|
+
...(loaded.error ? { error: loaded.error } : {}),
|
|
420
|
+
config: loaded.config,
|
|
421
|
+
// Convenience projection so the UI does not have to reach into config.
|
|
422
|
+
providerDefaults: loaded.config?.providerDefaults,
|
|
423
|
+
};
|
|
424
|
+
} catch (e: any) {
|
|
425
|
+
return { success: false, error: e.message };
|
|
426
|
+
}
|
|
427
|
+
},
|
|
428
|
+
|
|
429
|
+
// Partial-edit WRITE path for `.adhdev/mesh.json` `providerDefaults` — a
|
|
430
|
+
// READ-MODIFY-WRITE that preserves operator hand-edits. Unlike
|
|
431
|
+
// write_mesh_json_config (which rebuilds the WHOLE file from the machine-local
|
|
432
|
+
// scaffold and can silently drop hand-edited zones), this parses the existing
|
|
433
|
+
// repo file, merges ONLY the providerDefaults.autoApproveModes zone, and
|
|
434
|
+
// re-serializes — coordinator prompt, operating notes and limits authored in
|
|
435
|
+
// the repo are carried through untouched. Defaults to dry-run.
|
|
436
|
+
//
|
|
437
|
+
// args: { workspace?, autoApproveModes: Record<providerType,modeId>, write?, merge? }
|
|
438
|
+
// merge=true (default): per-provider merge into the existing map; a modeId of
|
|
439
|
+
// '' | null removes that provider's entry. merge=false: REPLACE the whole
|
|
440
|
+
// autoApproveModes map with the supplied one.
|
|
441
|
+
set_mesh_provider_defaults: async (_ctx: MedFamilyContext, args: any) => {
|
|
442
|
+
const workspace = typeof args?.workspace === 'string' && args.workspace.trim() ? args.workspace.trim() : process.cwd();
|
|
443
|
+
const write = args?.write === true;
|
|
444
|
+
const merge = args?.merge !== false; // default true
|
|
445
|
+
const inputModes = args?.autoApproveModes;
|
|
446
|
+
if (inputModes !== undefined && (typeof inputModes !== 'object' || inputModes === null || Array.isArray(inputModes))) {
|
|
447
|
+
return { success: false, error: 'autoApproveModes must be an object (providerType → modeId) when provided' };
|
|
448
|
+
}
|
|
449
|
+
try {
|
|
450
|
+
const {
|
|
451
|
+
loadRepoMeshJsonConfig,
|
|
452
|
+
normalizeRepoMeshDeclarativeConfig,
|
|
453
|
+
MESH_JSON_CONFIG_LOCATIONS,
|
|
454
|
+
} = await import('../../config/mesh-json-config.js');
|
|
455
|
+
const { existsSync, readFileSync, mkdirSync, writeFileSync } = await import('fs');
|
|
456
|
+
const { dirname, join } = await import('path');
|
|
457
|
+
const yaml = await import('js-yaml');
|
|
458
|
+
|
|
459
|
+
const relativePath = MESH_JSON_CONFIG_LOCATIONS[0];
|
|
460
|
+
|
|
461
|
+
// Read-modify-write: parse the EXISTING on-disk document (preferring the
|
|
462
|
+
// first existing json/yaml variant) so unrelated zones survive verbatim.
|
|
463
|
+
let baseDoc: Record<string, any> = { version: 1 };
|
|
464
|
+
let existingPath = join(workspace, relativePath);
|
|
465
|
+
let existedAsYaml = false;
|
|
466
|
+
for (const relative of MESH_JSON_CONFIG_LOCATIONS) {
|
|
467
|
+
const candidate = join(workspace, relative);
|
|
468
|
+
if (!existsSync(candidate)) continue;
|
|
469
|
+
try {
|
|
470
|
+
const text = readFileSync(candidate, 'utf-8');
|
|
471
|
+
const parsed = /\.json$/i.test(candidate) ? JSON.parse(text) : yaml.load(text);
|
|
472
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
473
|
+
baseDoc = parsed as Record<string, any>;
|
|
474
|
+
existingPath = candidate;
|
|
475
|
+
existedAsYaml = !/\.json$/i.test(candidate);
|
|
476
|
+
}
|
|
477
|
+
} catch (e: any) {
|
|
478
|
+
return { success: false, error: `existing ${relative} is unparseable, refusing to overwrite: ${e?.message || e}` };
|
|
479
|
+
}
|
|
480
|
+
break;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// Merge ONLY the providerDefaults.autoApproveModes zone.
|
|
484
|
+
const existingPd = baseDoc.providerDefaults && typeof baseDoc.providerDefaults === 'object' && !Array.isArray(baseDoc.providerDefaults)
|
|
485
|
+
? baseDoc.providerDefaults as Record<string, any>
|
|
486
|
+
: {};
|
|
487
|
+
const existingModes = existingPd.autoApproveModes && typeof existingPd.autoApproveModes === 'object' && !Array.isArray(existingPd.autoApproveModes)
|
|
488
|
+
? { ...existingPd.autoApproveModes as Record<string, string> }
|
|
489
|
+
: {};
|
|
490
|
+
|
|
491
|
+
const nextModes: Record<string, string> = merge ? existingModes : {};
|
|
492
|
+
if (inputModes) {
|
|
493
|
+
for (const [providerType, modeId] of Object.entries(inputModes as Record<string, unknown>)) {
|
|
494
|
+
const type = typeof providerType === 'string' ? providerType.trim() : '';
|
|
495
|
+
if (!type) continue;
|
|
496
|
+
const id = typeof modeId === 'string' ? modeId.trim() : '';
|
|
497
|
+
if (id) nextModes[type] = id;
|
|
498
|
+
else delete nextModes[type]; // '' / null → remove this provider's entry
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
const nextDoc: Record<string, any> = { ...baseDoc, version: 1 };
|
|
503
|
+
if (Object.keys(nextModes).length) {
|
|
504
|
+
nextDoc.providerDefaults = { ...existingPd, autoApproveModes: nextModes };
|
|
505
|
+
} else {
|
|
506
|
+
// No entries left → drop the zone entirely so we don't leave an empty stub.
|
|
507
|
+
if (nextDoc.providerDefaults) {
|
|
508
|
+
const { autoApproveModes, ...restPd } = nextDoc.providerDefaults;
|
|
509
|
+
if (Object.keys(restPd).length) nextDoc.providerDefaults = restPd;
|
|
510
|
+
else delete nextDoc.providerDefaults;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
// Validate the merged document before it ever touches disk.
|
|
515
|
+
const validation = normalizeRepoMeshDeclarativeConfig(nextDoc);
|
|
516
|
+
if (!validation.valid) {
|
|
517
|
+
return { success: false, error: `merged mesh.json is invalid: ${validation.errors.join('; ')}` };
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
// Serialize in the on-disk format (JSON unless the existing file was YAML).
|
|
521
|
+
const absolutePath = existingPath;
|
|
522
|
+
const serialized = existedAsYaml
|
|
523
|
+
? yaml.dump(nextDoc, { indent: 2 })
|
|
524
|
+
: `${JSON.stringify(nextDoc, null, 2)}\n`;
|
|
525
|
+
|
|
526
|
+
if (!write) {
|
|
527
|
+
return {
|
|
528
|
+
success: true,
|
|
529
|
+
written: false,
|
|
530
|
+
dryRun: true,
|
|
531
|
+
path: absolutePath,
|
|
532
|
+
relativePath,
|
|
533
|
+
merge,
|
|
534
|
+
providerDefaults: nextDoc.providerDefaults,
|
|
535
|
+
preview: serialized,
|
|
536
|
+
note: 'Dry-run: nothing written. Re-run with write=true to persist. Only the providerDefaults zone is merged; other repo zones are preserved.',
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
mkdirSync(dirname(absolutePath), { recursive: true });
|
|
541
|
+
writeFileSync(absolutePath, serialized, 'utf-8');
|
|
542
|
+
return {
|
|
543
|
+
success: true,
|
|
544
|
+
written: true,
|
|
545
|
+
dryRun: false,
|
|
546
|
+
path: absolutePath,
|
|
547
|
+
relativePath,
|
|
548
|
+
merge,
|
|
549
|
+
providerDefaults: nextDoc.providerDefaults,
|
|
550
|
+
note: 'Wrote providerDefaults into .adhdev/mesh.json (read-modify-write; other zones preserved). Commit it to the repo.',
|
|
551
|
+
};
|
|
552
|
+
} catch (e: any) {
|
|
553
|
+
return { success: false, error: e.message };
|
|
554
|
+
}
|
|
555
|
+
},
|
|
556
|
+
|
|
402
557
|
delete_mesh: async (_ctx: MedFamilyContext, args: any) => {
|
|
403
558
|
const meshId = typeof args?.meshId === 'string' ? args.meshId.trim() : '';
|
|
404
559
|
if (!meshId) return { success: false, error: 'meshId required' };
|
|
@@ -19,6 +19,18 @@
|
|
|
19
19
|
* machine-local policy directly. The repo file shapes the coordinator prompt and
|
|
20
20
|
* operating notes, nothing else.
|
|
21
21
|
*
|
|
22
|
+
* `providerDefaults` IS NOT POLICY EITHER. It is a repo-shared DECLARATIVE
|
|
23
|
+
* "requested auto-approve mode" per providerType — the answer to "WHEN a delegated
|
|
24
|
+
* worker of type X is auto-approved, WHICH mode should it use by default". It has
|
|
25
|
+
* NO say over WHETHER auto-approve is enabled: the ENABLE decision (and the
|
|
26
|
+
* dangerous-mode opt-in) remains 100% machine-local (meshes.json /
|
|
27
|
+
* RepoMeshPolicy). A repo can declare `providerDefaults` freely; a machine that
|
|
28
|
+
* has delegatedWorkerAutoApprove=false still gets no auto-approve, and a dangerous
|
|
29
|
+
* requested mode is still downgraded to PTY parsing unless the machine opts in.
|
|
30
|
+
* The requested mode ID is validated at runtime against the provider spec — an
|
|
31
|
+
* unknown mode ID is IGNORED (fall back to the provider's own default), never
|
|
32
|
+
* silently coerced into a dangerous mode.
|
|
33
|
+
*
|
|
22
34
|
* The coordinator/operatingNotes merge is **in-memory only**: the on-disk
|
|
23
35
|
* machine-local `meshes.json` is never mutated by this module.
|
|
24
36
|
*
|
|
@@ -60,6 +72,19 @@ export interface RepoMeshDeclarativeLimits {
|
|
|
60
72
|
maxNotes?: number;
|
|
61
73
|
}
|
|
62
74
|
|
|
75
|
+
/**
|
|
76
|
+
* Repo-shared declarative per-provider defaults. NOT policy — see the file header.
|
|
77
|
+
* `autoApproveModes` maps a providerType (e.g. "claude-cli") to the auto-approve
|
|
78
|
+
* mode ID that a delegated worker of that type should REQUEST when it is
|
|
79
|
+
* auto-approved. The map only influences WHICH mode is used, never WHETHER
|
|
80
|
+
* auto-approve is enabled (that stays machine-local). Mode IDs are validated
|
|
81
|
+
* against the live provider spec at resolve time; an unknown ID is ignored.
|
|
82
|
+
*/
|
|
83
|
+
export interface RepoMeshDeclarativeProviderDefaults {
|
|
84
|
+
/** providerType → requested auto-approve mode ID. */
|
|
85
|
+
autoApproveModes?: Record<string, string>;
|
|
86
|
+
}
|
|
87
|
+
|
|
63
88
|
/**
|
|
64
89
|
* Parsed + normalized `.adhdev/mesh.json` shape. Every field is optional except
|
|
65
90
|
* version so a repo can declare only the zone(s) it cares about. Policy is NOT a
|
|
@@ -70,6 +95,8 @@ export interface RepoMeshDeclarativeConfig {
|
|
|
70
95
|
coordinator?: RepoMeshDeclarativeCoordinatorConfig;
|
|
71
96
|
operatingNotes?: CoordinatorOperatingNote[];
|
|
72
97
|
limits?: RepoMeshDeclarativeLimits;
|
|
98
|
+
/** Repo-shared per-provider defaults (requested auto-approve mode). NOT policy. */
|
|
99
|
+
providerDefaults?: RepoMeshDeclarativeProviderDefaults;
|
|
73
100
|
}
|
|
74
101
|
|
|
75
102
|
export interface RepoMeshJsonConfigLoadResult {
|
|
@@ -132,6 +159,20 @@ export const MESH_JSON_CONFIG_SCHEMA = {
|
|
|
132
159
|
maxNotes: { type: 'number', minimum: 1 },
|
|
133
160
|
},
|
|
134
161
|
},
|
|
162
|
+
providerDefaults: {
|
|
163
|
+
type: 'object',
|
|
164
|
+
additionalProperties: false,
|
|
165
|
+
properties: {
|
|
166
|
+
// providerType → requested auto-approve mode ID. Mode IDs are
|
|
167
|
+
// validated against the live provider spec at resolve time; an
|
|
168
|
+
// unknown ID is ignored (provider default is used), so the schema
|
|
169
|
+
// only constrains the shape (string→string), not the ID values.
|
|
170
|
+
autoApproveModes: {
|
|
171
|
+
type: 'object',
|
|
172
|
+
additionalProperties: { type: 'string' },
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
},
|
|
135
176
|
},
|
|
136
177
|
} as const;
|
|
137
178
|
|
|
@@ -226,6 +267,38 @@ export function normalizeRepoMeshDeclarativeConfig(parsed: unknown): {
|
|
|
226
267
|
}
|
|
227
268
|
}
|
|
228
269
|
|
|
270
|
+
// providerDefaults: shape-only normalization. We keep every string→string
|
|
271
|
+
// (providerType → requested mode ID) entry after trimming; we deliberately do
|
|
272
|
+
// NOT validate the mode IDs against any provider spec here — the normalizer has
|
|
273
|
+
// no provider registry, and (crucially) validity depends on the LIVE provider
|
|
274
|
+
// at resolve time. The runtime resolver (resolveDelegatedWorkerAutoApprove)
|
|
275
|
+
// checks the requested ID against provider.autoApproveModes.modes and falls
|
|
276
|
+
// back to the provider's own default when the ID is unknown. This keeps the
|
|
277
|
+
// config fail-closed: a stale/typo'd mode ID never coerces into a dangerous
|
|
278
|
+
// mode, it just means "no repo override → provider default".
|
|
279
|
+
if (parsed.providerDefaults !== undefined) {
|
|
280
|
+
if (isRecord(parsed.providerDefaults)) {
|
|
281
|
+
const pd: RepoMeshDeclarativeProviderDefaults = {};
|
|
282
|
+
const rawModes = (parsed.providerDefaults as Record<string, unknown>).autoApproveModes;
|
|
283
|
+
if (rawModes !== undefined) {
|
|
284
|
+
if (isRecord(rawModes)) {
|
|
285
|
+
const modes: Record<string, string> = {};
|
|
286
|
+
for (const [providerType, modeId] of Object.entries(rawModes)) {
|
|
287
|
+
const type = typeof providerType === 'string' ? providerType.trim() : '';
|
|
288
|
+
const id = typeof modeId === 'string' ? modeId.trim() : '';
|
|
289
|
+
if (type && id) modes[type] = id;
|
|
290
|
+
}
|
|
291
|
+
if (Object.keys(modes).length) pd.autoApproveModes = modes;
|
|
292
|
+
} else {
|
|
293
|
+
errors.push('providerDefaults.autoApproveModes must be an object when provided');
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
if (Object.keys(pd).length) config.providerDefaults = pd;
|
|
297
|
+
} else {
|
|
298
|
+
errors.push('providerDefaults must be an object when provided');
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
229
302
|
return { valid: true, config, errors };
|
|
230
303
|
}
|
|
231
304
|
|
|
@@ -364,6 +437,21 @@ export function applyRepoMeshConfig<T extends Pick<LocalMeshEntry, 'coordinator'
|
|
|
364
437
|
* exported — it is machine-local only and has no place in mesh.json. Operating
|
|
365
438
|
* notes are intentionally NOT exported either: those are runtime ledger lessons,
|
|
366
439
|
* and a repo should declare baseline notes deliberately.
|
|
440
|
+
*
|
|
441
|
+
* `providerDefaults` is NOT auto-exported from the machine-local mesh (there is no
|
|
442
|
+
* machine-local source for it — it is a repo-authored declaration). To help an
|
|
443
|
+
* operator hand-author it, the scaffold carries a commented example shape:
|
|
444
|
+
*
|
|
445
|
+
* "providerDefaults": {
|
|
446
|
+
* "autoApproveModes": {
|
|
447
|
+
* "claude-cli": "accept-edits", // requested mode WHEN auto-approve is on
|
|
448
|
+
* "codex-cli": "auto" // (enable/dangerous opt-in stays machine-local)
|
|
449
|
+
* }
|
|
450
|
+
* }
|
|
451
|
+
*
|
|
452
|
+
* The example is surfaced via the scaffold's `_providerDefaultsExample` hint (JSON
|
|
453
|
+
* has no comments) rather than a live `providerDefaults` value, so serializing the
|
|
454
|
+
* scaffold never writes an unwanted requested-mode map into the repo file.
|
|
367
455
|
*/
|
|
368
456
|
export function buildMeshJsonConfigScaffold(
|
|
369
457
|
mesh: Pick<LocalMeshEntry, 'coordinator'>,
|
|
@@ -378,6 +466,21 @@ export function buildMeshJsonConfigScaffold(
|
|
|
378
466
|
return scaffold;
|
|
379
467
|
}
|
|
380
468
|
|
|
469
|
+
/**
|
|
470
|
+
* A copy-paste example of the `providerDefaults` zone for operators hand-authoring
|
|
471
|
+
* a repo `.adhdev/mesh.json`. Returned by the export/write commands as a separate
|
|
472
|
+
* hint field (never merged into the serialized scaffold) so the repo file stays
|
|
473
|
+
* clean. The mode IDs shown are illustrative — a repo should use IDs that exist in
|
|
474
|
+
* its own providers' specs; an unknown ID is ignored at resolve time and the
|
|
475
|
+
* provider's own default is used.
|
|
476
|
+
*/
|
|
477
|
+
export const MESH_JSON_PROVIDER_DEFAULTS_EXAMPLE: RepoMeshDeclarativeProviderDefaults = {
|
|
478
|
+
autoApproveModes: {
|
|
479
|
+
'claude-cli': 'accept-edits',
|
|
480
|
+
'codex-cli': 'auto',
|
|
481
|
+
},
|
|
482
|
+
};
|
|
483
|
+
|
|
381
484
|
/** Serialize a scaffold to the canonical 2-space JSON draft text. */
|
|
382
485
|
export function serializeMeshJsonConfigScaffold(config: RepoMeshDeclarativeConfig): string {
|
|
383
486
|
return JSON.stringify(config, null, 2);
|
package/src/index.ts
CHANGED
|
@@ -143,6 +143,8 @@ export type {
|
|
|
143
143
|
export {
|
|
144
144
|
DEFAULT_MESH_POLICY,
|
|
145
145
|
resolveDelegatedWorkerAutoApprove,
|
|
146
|
+
delegatedWorkerAutoApproveSettings,
|
|
147
|
+
resolveDelegatedWorkerDangerousModeAllow,
|
|
146
148
|
resolveAllowSendKeysDestructive,
|
|
147
149
|
resolveMagiSessionCleanupMode,
|
|
148
150
|
magiAutoLaunchedSessionCleanupDecision,
|
|
@@ -161,6 +163,24 @@ export {
|
|
|
161
163
|
resolveAutoConvergeCodeChange,
|
|
162
164
|
} from './repo-mesh-types.js';
|
|
163
165
|
|
|
166
|
+
// ── Repo-shared declarative mesh config (.adhdev/mesh.json) ──
|
|
167
|
+
export {
|
|
168
|
+
loadRepoMeshJsonConfig,
|
|
169
|
+
normalizeRepoMeshDeclarativeConfig,
|
|
170
|
+
buildMeshJsonConfigScaffold,
|
|
171
|
+
serializeMeshJsonConfigScaffold,
|
|
172
|
+
MESH_JSON_CONFIG_LOCATIONS,
|
|
173
|
+
MESH_JSON_CONFIG_SCHEMA,
|
|
174
|
+
MESH_JSON_PROVIDER_DEFAULTS_EXAMPLE,
|
|
175
|
+
} from './config/mesh-json-config.js';
|
|
176
|
+
export type {
|
|
177
|
+
RepoMeshDeclarativeConfig,
|
|
178
|
+
RepoMeshDeclarativeCoordinatorConfig,
|
|
179
|
+
RepoMeshDeclarativeLimits,
|
|
180
|
+
RepoMeshDeclarativeProviderDefaults,
|
|
181
|
+
RepoMeshJsonConfigLoadResult,
|
|
182
|
+
} from './config/mesh-json-config.js';
|
|
183
|
+
|
|
164
184
|
// ── Git Surface ──
|
|
165
185
|
export * from './git/index.js';
|
|
166
186
|
|
|
@@ -489,7 +509,7 @@ export { ProviderInstanceManager } from './providers/provider-instance-manager.j
|
|
|
489
509
|
export { IdeProviderInstance } from './providers/ide-provider-instance.js';
|
|
490
510
|
export { CliProviderInstance } from './providers/cli-provider-instance.js';
|
|
491
511
|
export { AcpProviderInstance } from './providers/acp-provider-instance.js';
|
|
492
|
-
export type { ProviderModule, CdpTargetFilter, ProviderResumeCapability, InputEnvelope, InputPart, MessagePart, ReadChatTurnStatus, ControlListResult, ControlSetResult, ControlInvokeResult } from './providers/contracts.js';
|
|
512
|
+
export type { ProviderModule, AutoApproveMode, AutoApproveModesConfig, AutoApproveModeRisk, AutoApproveModeStrategy, CdpTargetFilter, ProviderResumeCapability, InputEnvelope, InputPart, MessagePart, ReadChatTurnStatus, ControlListResult, ControlSetResult, ControlInvokeResult } from './providers/contracts.js';
|
|
493
513
|
export type { ProviderSourceConfigSnapshot, ProviderSourceConfigUpdate } from './config/provider-source-config.js';
|
|
494
514
|
export { parseProviderSourceConfigUpdate } from './config/provider-source-config.js';
|
|
495
515
|
export { normalizeInputEnvelope, normalizeMessageParts, flattenMessageParts } from './providers/io-contracts.js';
|