@agentxm/workspace-state 0.28.4-bootstrap.0 → 0.28.5
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/src/index.d.ts +2 -1
- package/dist/src/index.js +2 -1
- package/dist/src/lockfile/lockfile.d.ts +3 -3
- package/dist/src/lockfile/schema.d.ts +5 -4
- package/dist/src/lockfile/schema.js +5 -4
- package/dist/src/workspace/accepted-canonical-ref.d.ts +3 -3
- package/dist/src/workspace/accepted-canonical-ref.js +2 -2
- package/dist/src/workspace/canonical-observation.js +8 -5
- package/dist/src/workspace/desired-state-graph.d.ts +13 -1
- package/dist/src/workspace/desired-state-graph.js +80 -10
- package/dist/src/workspace/mcp-source-identity.d.ts +17 -0
- package/dist/src/workspace/mcp-source-identity.js +40 -0
- package/dist/src/workspace/read-model/__fixtures__/builder.js +1 -1
- package/dist/src/workspace/read-model/errors.d.ts +12 -2
- package/dist/src/workspace/read-model/errors.js +3 -0
- package/dist/src/workspace/read-model/extensions/mcp-server.js +46 -11
- package/dist/src/workspace/read-model/state.js +18 -2
- package/dist/src/workspace/read-model/types.d.ts +1 -1
- package/dist/src/workspace/service-interface.d.ts +9 -5
- package/dist/src/workspace/service.d.ts +241 -8
- package/dist/src/workspace/service.js +50 -14
- package/dist/src/workspace/test-stubs.js +3 -2
- package/package.json +5 -3
package/dist/src/index.d.ts
CHANGED
|
@@ -54,6 +54,7 @@ export { hookLockEntryToRef, knowledgeLockEntryToRef, mcpServerLockEntryToRef, p
|
|
|
54
54
|
export { lockEntryToSourceParams, printSkillLockSourceLocator, } from "./workspace/lock-entry-to-source-params.js";
|
|
55
55
|
export { sourceToLockEntry, type SourceToLockEntryInput, } from "./workspace/source-to-lock-entry.js";
|
|
56
56
|
export { deriveSourceMetaFromLockType, type SourceMeta } from "./workspace/source-metadata.js";
|
|
57
|
+
export { mcpRegistryResolutionKey, mcpResolutionKey } from "./workspace/mcp-source-identity.js";
|
|
57
58
|
export { READ_MODEL_EXTENSION_FAMILY_BY_TYPE, makeWorkspaceReadModel, WorkspaceReadModelConfig, type RawSourceBytes, type ScopedOwnerApi, type ScopedSourceHostsApi, type ScopedStateApi, type WorkspaceReadModel, type WorkspaceReadModelConfigService, } from "./workspace/read-model/service.js";
|
|
58
59
|
export { AgentRootResolver, AgentRootResolverLive, } from "./workspace/read-model/agent-root-resolver.js";
|
|
59
60
|
export { ExtensionInventoryClassificationSchema, ExtensionInventoryLifecycleSchema, ExtensionInventoryRowSchema, ExtensionInventorySchema, projectExtensionInventory, type ExtensionInventory, type ExtensionInventoryClassification, type ExtensionInventoryLifecycle, type ExtensionInventoryObservation, type ExtensionInventoryRow, type LifecycleInventoryCandidate, type ProjectExtensionInventoryInput, } from "./workspace/read-model/extensions/inventory.js";
|
|
@@ -62,7 +63,7 @@ export type { ActualMcpServer, ActualPack, ActualSkill, ActualSubagent, Installe
|
|
|
62
63
|
export type { FileSpec, FixtureSpec, ScopeFiles, TreeFiles, } from "./workspace/read-model/__fixtures__/builder.js";
|
|
63
64
|
export { WorkspaceMutations, type MakeWorkspaceTransactionCapabilities, type WorkspaceMutationsService, type WorkspaceMutationsError, type WorkspaceMutationsOptions, type WorkspaceSettingsReadFailure, type WorkspaceLockfileReadFailure, type WorkspaceStateReadFailure, type WorkspaceSettingsMutationFailure, type WorkspaceLockfileMutationFailure, type WorkspaceStateMutationFailure, type SetSkillArgs, type SetPackArgs, type SetMcpServerArgs, type SetSubagentArgs, type PackDirPath, type ExtensionTarget, type ExtensionTargetFor, type LockfileState, type WorkspaceTransactionRunner, type WorkspaceTransactionCapabilities, type WorkspaceTransitionAcquirer, type WorkspaceTransitionRequest, type WorkspaceLifecycleTransactionArgs, type SkillExtensionTarget, type PackExtensionTarget, type McpServerExtensionTarget, type SubagentExtensionTarget, type RuleExtensionTarget, type HookExtensionTarget, type KnowledgeExtensionTarget, } from "./workspace/service-interface.js";
|
|
64
65
|
export { makeWorkspaceMutations, type WorkspaceLayerOptions } from "./workspace/service.js";
|
|
65
|
-
export { LockfileDecodeError, LockfileIoError, LockfileParseError, SettingsDecodeError, SettingsIoError, SettingsParseError, SkillDiscoveryRootInvalid, SubagentScanFailed, WorkspaceRootEscape, type LockfileReadError, type SettingsReadError, } from "./workspace/read-model/errors.js";
|
|
66
|
+
export { LockfileDecodeError, LockfileIoError, LockfileParseError, LockfileVersionUnsupported, SettingsDecodeError, SettingsIoError, SettingsParseError, SkillDiscoveryRootInvalid, SubagentScanFailed, WorkspaceRootEscape, type LockfileReadError, type SettingsReadError, } from "./workspace/read-model/errors.js";
|
|
66
67
|
export { AcceptedResolutionMissing, CanonicalPathRemovalError, DesiredPackGraphIncomplete, InlineExtensionSourceMissing, InvalidAgentId, LockedSkillMissing, LockEntryEndpointConflict, LockEntryNameInvalid, LockEntrySourceMissing, LockEntrySourceTypeConflict, LockEntryUrlInvalid, PackageContentHashFailed, SettingsEntryMissing, SupersededCanonicalRemovalFailed, SymlinkCreationError, WorkspaceLayoutError, WorkspaceNotInitialized, WorkspaceSourceInvalid, } from "./workspace/errors.js";
|
|
67
68
|
export { CurrentWorkspaceClosure, CurrentWorkspaceTransaction, protectCreatedAncestors, protectInContext, protectWorkspacePath, readPendingClosureRestorationFailures, type Snapshot, type WorkspaceTransactionContext, TransitionLockError, TransitionLockUnavailable, WorkspaceDirectoryError, WorkspaceRestorationError, WorkspaceRestorationIncomplete, WorkspaceSnapshotError, WorkspaceTransitionCompromised, type TransitionContention, type TransitionLockHolder, type WorkspaceTransactionFailure, type WorkspaceTransitionAcquireFailure, } from "./workspace/transaction.js";
|
|
68
69
|
export { setupScopeSupport, setupScopeSupportOutcomes, type SetupScopeSupportCategory, type SetupScopeSupportOutcome, type SetupScopeSupportReasonCode, type SetupScopeSupportStatus, } from "./workspace/setup-scope-support.js";
|
package/dist/src/index.js
CHANGED
|
@@ -67,6 +67,7 @@ export { lockEntryToSourceParams, printSkillLockSourceLocator, } from "./workspa
|
|
|
67
67
|
export { sourceToLockEntry, } from "./workspace/source-to-lock-entry.js";
|
|
68
68
|
// Source metadata
|
|
69
69
|
export { deriveSourceMetaFromLockType } from "./workspace/source-metadata.js";
|
|
70
|
+
export { mcpRegistryResolutionKey, mcpResolutionKey } from "./workspace/mcp-source-identity.js";
|
|
70
71
|
// Workspace read model
|
|
71
72
|
export { READ_MODEL_EXTENSION_FAMILY_BY_TYPE, makeWorkspaceReadModel, WorkspaceReadModelConfig, } from "./workspace/read-model/service.js";
|
|
72
73
|
export { AgentRootResolver, AgentRootResolverLive, } from "./workspace/read-model/agent-root-resolver.js";
|
|
@@ -76,7 +77,7 @@ export { getPriorityDirectories, parsePluginManifests, scanAgentSubagentFiles, s
|
|
|
76
77
|
export { WorkspaceMutations, } from "./workspace/service-interface.js";
|
|
77
78
|
export { makeWorkspaceMutations } from "./workspace/service.js";
|
|
78
79
|
// Read-model per-source typed failure families
|
|
79
|
-
export { LockfileDecodeError, LockfileIoError, LockfileParseError, SettingsDecodeError, SettingsIoError, SettingsParseError, SkillDiscoveryRootInvalid, SubagentScanFailed, WorkspaceRootEscape, } from "./workspace/read-model/errors.js";
|
|
80
|
+
export { LockfileDecodeError, LockfileIoError, LockfileParseError, LockfileVersionUnsupported, SettingsDecodeError, SettingsIoError, SettingsParseError, SkillDiscoveryRootInvalid, SubagentScanFailed, WorkspaceRootEscape, } from "./workspace/read-model/errors.js";
|
|
80
81
|
// Workspace-state typed failure families
|
|
81
82
|
export { AcceptedResolutionMissing, CanonicalPathRemovalError, DesiredPackGraphIncomplete, InlineExtensionSourceMissing, InvalidAgentId, LockedSkillMissing, LockEntryEndpointConflict, LockEntryNameInvalid, LockEntrySourceMissing, LockEntrySourceTypeConflict, LockEntryUrlInvalid, PackageContentHashFailed, SettingsEntryMissing, SupersededCanonicalRemovalFailed, SymlinkCreationError, WorkspaceLayoutError, WorkspaceNotInitialized, WorkspaceSourceInvalid, } from "./workspace/errors.js";
|
|
82
83
|
// Workspace transaction registration (the WS half of the transaction seam)
|
|
@@ -173,7 +173,7 @@ export declare const commitLockfileUpdates: (axmDir: string, lockfile: Lockfile,
|
|
|
173
173
|
readonly treeIntegrity: string & import("effect/Brand").Brand<"TreeIntegrity">;
|
|
174
174
|
};
|
|
175
175
|
};
|
|
176
|
-
readonly lockfileVersion:
|
|
176
|
+
readonly lockfileVersion: 7;
|
|
177
177
|
readonly knowledge?: {
|
|
178
178
|
readonly [x: string]: {
|
|
179
179
|
readonly type: "github";
|
|
@@ -913,7 +913,7 @@ export declare const commitLockfileSnapshotUpdateAtPath: (lockfilePath: string,
|
|
|
913
913
|
readonly treeIntegrity: string & import("effect/Brand").Brand<"TreeIntegrity">;
|
|
914
914
|
};
|
|
915
915
|
};
|
|
916
|
-
readonly lockfileVersion:
|
|
916
|
+
readonly lockfileVersion: 7;
|
|
917
917
|
readonly knowledge?: {
|
|
918
918
|
readonly [x: string]: {
|
|
919
919
|
readonly type: "github";
|
|
@@ -1642,7 +1642,7 @@ export declare const commitLockfileSnapshotUpdate: (axmDir: string, base: Lockfi
|
|
|
1642
1642
|
readonly treeIntegrity: string & import("effect/Brand").Brand<"TreeIntegrity">;
|
|
1643
1643
|
};
|
|
1644
1644
|
};
|
|
1645
|
-
readonly lockfileVersion:
|
|
1645
|
+
readonly lockfileVersion: 7;
|
|
1646
1646
|
readonly knowledge?: {
|
|
1647
1647
|
readonly [x: string]: {
|
|
1648
1648
|
readonly type: "github";
|
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
* The lockfile (axm-lock.yaml) records accepted immutable resolutions for
|
|
5
5
|
* externally sourced extensions.
|
|
6
6
|
*
|
|
7
|
-
* Lockfile
|
|
7
|
+
* Lockfile v7 is authority, not receipt history. It contains no authored,
|
|
8
8
|
* bundled, inline, projection, completion-time, or command-history state.
|
|
9
9
|
*
|
|
10
10
|
* @experimental This API is unstable and may change without notice.
|
|
11
11
|
*/
|
|
12
12
|
import * as Schema from "effect/Schema";
|
|
13
|
-
export declare const LOCKFILE_VERSION =
|
|
13
|
+
export declare const LOCKFILE_VERSION = 7;
|
|
14
14
|
/**
|
|
15
15
|
* Lock entry for a single installed skill.
|
|
16
16
|
* Discriminated union by the `type` field.
|
|
@@ -667,7 +667,8 @@ export declare const McpServerLockEntrySchema: Schema.Union<readonly [Schema.Str
|
|
|
667
667
|
*/
|
|
668
668
|
export type McpServerLockEntry = Schema.Schema.Type<typeof McpServerLockEntrySchema>;
|
|
669
669
|
/**
|
|
670
|
-
* Map of MCP
|
|
670
|
+
* Map of canonical MCP source-resolution identities to their lock entries.
|
|
671
|
+
* Local connection names live only in settings and native projections.
|
|
671
672
|
*
|
|
672
673
|
* @experimental This API is unstable and may change without notice.
|
|
673
674
|
*/
|
|
@@ -2339,7 +2340,7 @@ export declare const LOCK_ENTRY_SCHEMA_BY_TYPE: {
|
|
|
2339
2340
|
}>]>;
|
|
2340
2341
|
};
|
|
2341
2342
|
export declare const LockfileSchema: Schema.Struct<{
|
|
2342
|
-
readonly lockfileVersion: Schema.Literal<
|
|
2343
|
+
readonly lockfileVersion: Schema.Literal<7>;
|
|
2343
2344
|
readonly skills: Schema.$Record<Schema.String, Schema.Union<readonly [Schema.Struct<{
|
|
2344
2345
|
readonly type: Schema.Literal<"github">;
|
|
2345
2346
|
readonly sourceType: Schema.Literal<"github">;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* The lockfile (axm-lock.yaml) records accepted immutable resolutions for
|
|
5
5
|
* externally sourced extensions.
|
|
6
6
|
*
|
|
7
|
-
* Lockfile
|
|
7
|
+
* Lockfile v7 is authority, not receipt history. It contains no authored,
|
|
8
8
|
* bundled, inline, projection, completion-time, or command-history state.
|
|
9
9
|
*
|
|
10
10
|
* @experimental This API is unstable and may change without notice.
|
|
@@ -16,7 +16,7 @@ import { TreeIntegritySchema } from "../workspace/materialized-tree.js";
|
|
|
16
16
|
import { ExtensionNameSchema } from "@agentxm/extension-model/unstable/extensions/common";
|
|
17
17
|
import { VersionSchema } from "@agentxm/extension-model/unstable/version-constraints";
|
|
18
18
|
import { SourceNamespaceSchema, SourceRefSchema, SourceSegmentSchema, SourceSubPathSchema, } from "@agentxm/extension-model/unstable/sources/types";
|
|
19
|
-
export const LOCKFILE_VERSION =
|
|
19
|
+
export const LOCKFILE_VERSION = 7;
|
|
20
20
|
// =============================================================================
|
|
21
21
|
// Flat Source Schemas (discriminated by type field)
|
|
22
22
|
// =============================================================================
|
|
@@ -234,7 +234,8 @@ export const McpServerLockEntrySchema = makeSourceLockUnion("mcp-server", Handle
|
|
|
234
234
|
// MCP Servers Lock Map
|
|
235
235
|
// =============================================================================
|
|
236
236
|
/**
|
|
237
|
-
* Map of MCP
|
|
237
|
+
* Map of canonical MCP source-resolution identities to their lock entries.
|
|
238
|
+
* Local connection names live only in settings and native projections.
|
|
238
239
|
*
|
|
239
240
|
* @experimental This API is unstable and may change without notice.
|
|
240
241
|
*/
|
|
@@ -379,7 +380,7 @@ export const LOCK_ENTRY_SCHEMA_BY_TYPE = {
|
|
|
379
380
|
* enabling reproducible installations across environments.
|
|
380
381
|
*
|
|
381
382
|
* Structure:
|
|
382
|
-
* - lockfileVersion: Schema version (currently
|
|
383
|
+
* - lockfileVersion: Schema version (currently 7)
|
|
383
384
|
* - skills: Map of skill names to their lock entries
|
|
384
385
|
* - packs: Map of pack names to their lock entries (optional)
|
|
385
386
|
*
|
|
@@ -9,7 +9,7 @@ import type { WorkspaceSnapshotError } from "./transaction.js";
|
|
|
9
9
|
import { type LockEntryToRefError } from "./lock-entry-to-ref.js";
|
|
10
10
|
import { type AcceptedExtensionResolution, type CanonicalObservation } from "./canonical-observation.js";
|
|
11
11
|
import type { DesiredExtensionNode } from "./desired-state-graph.js";
|
|
12
|
-
import type {
|
|
12
|
+
import type { WorkspaceMutationsService, WorkspaceStateReadFailure } from "./service-interface.js";
|
|
13
13
|
interface AcceptedCanonicalRefArgs {
|
|
14
14
|
readonly workspace: WorkspaceMutationsService;
|
|
15
15
|
readonly type: DesiredExtensionNode["type"];
|
|
@@ -34,7 +34,7 @@ export interface UsableAcceptedCanonical extends UsableAcceptedCanonicalObservat
|
|
|
34
34
|
/** Canonical package AXM may delete when removing desired state. Authored source is durable. */
|
|
35
35
|
export declare const removableAcceptedCanonicalPath: (canonical: Option.Option<AcceptedCanonicalObservation>) => Option.Option<string>;
|
|
36
36
|
/** Exact acquired canonical path reconstructed directly from accepted lock authority. */
|
|
37
|
-
export declare const acceptedLockedCanonicalPath: (args: AcceptedCanonicalRefArgs) => Effect.Effect<Option.Option<string>,
|
|
37
|
+
export declare const acceptedLockedCanonicalPath: (args: AcceptedCanonicalRefArgs) => Effect.Effect<Option.Option<string>, WorkspaceStateReadFailure, Path.Path>;
|
|
38
38
|
/**
|
|
39
39
|
* Capture exact cleanup for a superseded accepted package. The old path is
|
|
40
40
|
* read before the lock transition; the returned effect runs afterward and
|
|
@@ -42,7 +42,7 @@ export declare const acceptedLockedCanonicalPath: (args: AcceptedCanonicalRefArg
|
|
|
42
42
|
*/
|
|
43
43
|
export declare const prepareAcceptedCanonicalTransition: (args: AcceptedCanonicalRefArgs & {
|
|
44
44
|
readonly ref: ExtensionRef;
|
|
45
|
-
}) => Effect.Effect<Effect.Effect<void, WorkspaceSnapshotError | SupersededCanonicalRemovalFailed>,
|
|
45
|
+
}) => Effect.Effect<Effect.Effect<void, WorkspaceSnapshotError | SupersededCanonicalRemovalFailed>, WorkspaceStateReadFailure, FileSystem.FileSystem | Path.Path>;
|
|
46
46
|
/** Reconstruct a ref directly from accepted lock authority without desired reachability. */
|
|
47
47
|
export declare const acceptedLockedResolutionRef: (args: AcceptedCanonicalRefArgs) => Effect.Effect<Option.Option<ExtensionRef>, AcceptedCanonicalRefError, FileSystem.FileSystem | Path.Path>;
|
|
48
48
|
/**
|
|
@@ -21,7 +21,7 @@ const getAcceptedResolution = (workspace, type, name) => {
|
|
|
21
21
|
case "skill":
|
|
22
22
|
return workspace.getLockedSkill(name);
|
|
23
23
|
case "mcp-server":
|
|
24
|
-
return workspace.
|
|
24
|
+
return workspace.getLockedMcpServerForConnection(name);
|
|
25
25
|
case "subagent":
|
|
26
26
|
return workspace.getLockedSubagent(name);
|
|
27
27
|
case "rule":
|
|
@@ -101,7 +101,7 @@ const refFromAcceptedResolution = (workspace, type, name) => Effect.gen(function
|
|
|
101
101
|
});
|
|
102
102
|
}
|
|
103
103
|
case "mcp-server": {
|
|
104
|
-
const entry = yield* workspace.
|
|
104
|
+
const entry = yield* workspace.getLockedMcpServerForConnection(name);
|
|
105
105
|
return yield* Option.match(entry, {
|
|
106
106
|
onNone: () => Effect.fail(missingAccepted("MCP", name)),
|
|
107
107
|
onSome: (value) => mcpServerLockEntryToRef(name, value, deps),
|
|
@@ -19,6 +19,7 @@ import { printSourceParams } from "@agentxm/extension-model/unstable/sources/pri
|
|
|
19
19
|
import { lockEntryToSourceParams } from "./lock-entry-to-source-params.js";
|
|
20
20
|
import { collectDesiredConstraintContributors, } from "./desired-state-graph.js";
|
|
21
21
|
import { computeExtensionPathsForLayout, extensionPathSourceFromLockEntry, } from "./extension-paths.js";
|
|
22
|
+
import { mcpResolutionKey } from "./mcp-source-identity.js";
|
|
22
23
|
const MANIFEST_CONTRACTS = {
|
|
23
24
|
skill: { filename: "skill.json", schema: SkillManifestSchema },
|
|
24
25
|
"mcp-server": { filename: "mcp.json", schema: McpServerManifestSchema },
|
|
@@ -100,11 +101,13 @@ export const observeCanonicalExtension = ({ layout, desired, accepted, }) => Eff
|
|
|
100
101
|
status: "missing-resolution",
|
|
101
102
|
};
|
|
102
103
|
}
|
|
103
|
-
const acceptedIdentity = accepted?.
|
|
104
|
-
?
|
|
105
|
-
: accepted ===
|
|
106
|
-
?
|
|
107
|
-
:
|
|
104
|
+
const acceptedIdentity = accepted?.extensionType === "mcp-server"
|
|
105
|
+
? mcpResolutionKey(accepted)
|
|
106
|
+
: accepted?.type === "registry"
|
|
107
|
+
? `${accepted.owner}/${toExtensionTypePlural(desired.type)}/${accepted.name}`
|
|
108
|
+
: accepted === undefined
|
|
109
|
+
? undefined
|
|
110
|
+
: printSourceParams(lockEntryToSourceParams(accepted));
|
|
108
111
|
if (!workspaceAuthored &&
|
|
109
112
|
!bundled &&
|
|
110
113
|
acceptedIdentity !== desired.identity &&
|
|
@@ -7,12 +7,14 @@ import type { Settings } from "../settings/index.js";
|
|
|
7
7
|
import { type WorkspaceLayout } from "./layout.js";
|
|
8
8
|
export type DesiredExtensionOrigin = {
|
|
9
9
|
readonly type: "settings";
|
|
10
|
+
readonly localName?: string;
|
|
10
11
|
readonly authority?: "sourced";
|
|
11
12
|
readonly source: string;
|
|
12
13
|
readonly enabled: boolean;
|
|
13
14
|
readonly constraint?: string;
|
|
14
15
|
} | {
|
|
15
16
|
readonly type: "settings";
|
|
17
|
+
readonly localName?: string;
|
|
16
18
|
readonly authority: "inline";
|
|
17
19
|
readonly source?: undefined;
|
|
18
20
|
readonly constraint?: undefined;
|
|
@@ -52,6 +54,7 @@ export interface DesiredConstraintContributor {
|
|
|
52
54
|
readonly range: string;
|
|
53
55
|
readonly location: string;
|
|
54
56
|
readonly dependingPack?: string;
|
|
57
|
+
readonly localName?: string;
|
|
55
58
|
}
|
|
56
59
|
export type DesiredStateProblem = {
|
|
57
60
|
readonly type: "workspace-owner-missing";
|
|
@@ -98,8 +101,15 @@ export type DesiredStateProblem = {
|
|
|
98
101
|
export interface DesiredStateGraph {
|
|
99
102
|
readonly complete: boolean;
|
|
100
103
|
readonly nodes: ReadonlyArray<DesiredExtensionNode>;
|
|
104
|
+
readonly mcpSourceClosures: ReadonlyArray<DesiredMcpSourceClosure>;
|
|
101
105
|
readonly problems: ReadonlyArray<DesiredStateProblem>;
|
|
102
106
|
}
|
|
107
|
+
export interface DesiredMcpSourceClosure {
|
|
108
|
+
readonly identity: string;
|
|
109
|
+
readonly localNames: ReadonlyArray<string>;
|
|
110
|
+
readonly constraints: ReadonlyArray<string>;
|
|
111
|
+
readonly origins: ReadonlyArray<DesiredExtensionOrigin>;
|
|
112
|
+
}
|
|
103
113
|
export type ProspectivePackRef = Pick<PackRef, "owner" | "pack" | "version">;
|
|
104
114
|
interface DesiredStateGraphArgs {
|
|
105
115
|
readonly baseDir: string;
|
|
@@ -107,8 +117,10 @@ interface DesiredStateGraphArgs {
|
|
|
107
117
|
readonly layout?: WorkspaceLayout;
|
|
108
118
|
/** Resolved Pack roots whose manifests supersede the currently materialized copy. */
|
|
109
119
|
readonly prospectivePacks?: ReadonlyArray<ProspectivePackRef>;
|
|
120
|
+
/** Registry source aliases mapped to their stable authority endpoints. */
|
|
121
|
+
readonly registryAuthorities?: Readonly<Record<string, URL | string>>;
|
|
110
122
|
}
|
|
111
123
|
export declare const collectDesiredConstraintContributors: (_path: Path.Path, origins: ReadonlyArray<DesiredExtensionOrigin>) => ReadonlyArray<DesiredConstraintContributor>;
|
|
112
|
-
export declare const buildDesiredStateGraph: ({ baseDir, settings, layout, prospectivePacks, }: DesiredStateGraphArgs) => Effect.Effect<DesiredStateGraph, never, FileSystem.FileSystem | Path.Path>;
|
|
124
|
+
export declare const buildDesiredStateGraph: ({ baseDir, settings, layout, prospectivePacks, registryAuthorities, }: DesiredStateGraphArgs) => Effect.Effect<DesiredStateGraph, never, FileSystem.FileSystem | Path.Path>;
|
|
113
125
|
export {};
|
|
114
126
|
//# sourceMappingURL=desired-state-graph.d.ts.map
|
|
@@ -13,6 +13,7 @@ import { configuredAuthoredDirectory } from "./layout.js";
|
|
|
13
13
|
import { SETTINGS_FILENAME } from "@agentxm/extension-model/unstable/workspace-files";
|
|
14
14
|
import { ACQUIRED_EXTENSIONS_DIR } from "./constants.js";
|
|
15
15
|
import { intersectVersionConstraints } from "@agentxm/extension-model/unstable/version-constraints";
|
|
16
|
+
import { mcpRegistryResolutionKey } from "./mcp-source-identity.js";
|
|
16
17
|
export const isInlineDesiredExtension = (node) => node.authority === "inline";
|
|
17
18
|
export const isSourcedDesiredExtension = (node) => node.authority !== "inline";
|
|
18
19
|
const nodeKey = (type, name) => `${type}:${name}`;
|
|
@@ -26,7 +27,17 @@ const registryLocator = (source) => {
|
|
|
26
27
|
const ref = source.slice(separator + 1);
|
|
27
28
|
return ref.startsWith("@") ? { sourceName: source.slice(0, separator), ref } : undefined;
|
|
28
29
|
};
|
|
29
|
-
const
|
|
30
|
+
const withVersionConstraint = (source, constraint) => {
|
|
31
|
+
const locator = registryLocator(source);
|
|
32
|
+
if (locator === undefined)
|
|
33
|
+
return source;
|
|
34
|
+
const parsed = parseRegistrySourceRef(locator.ref);
|
|
35
|
+
if (parsed === undefined)
|
|
36
|
+
return source;
|
|
37
|
+
const prefix = source.startsWith("@") ? "" : `${locator.sourceName}:`;
|
|
38
|
+
return `${prefix}${parsed.owner}/${parsed.type}/${parsed.name}@${constraint}`;
|
|
39
|
+
};
|
|
40
|
+
const sourceIdentity = (type, name, source, settings, registryAuthorities) => {
|
|
30
41
|
if (isWorkspaceSourceLocator(source)) {
|
|
31
42
|
return settings.owner === undefined
|
|
32
43
|
? { identity: source }
|
|
@@ -35,8 +46,15 @@ const sourceIdentity = (type, name, source, settings) => {
|
|
|
35
46
|
const locator = registryLocator(source);
|
|
36
47
|
const parsed = locator === undefined ? undefined : parseRegistrySourceRef(locator.ref);
|
|
37
48
|
if (parsed !== undefined && parsed.type === toExtensionTypePlural(type)) {
|
|
49
|
+
const registryAuthority = locator === undefined ? undefined : registryAuthorities[locator.sourceName];
|
|
38
50
|
return {
|
|
39
|
-
identity:
|
|
51
|
+
identity: type === "mcp-server" && registryAuthority !== undefined
|
|
52
|
+
? mcpRegistryResolutionKey({
|
|
53
|
+
authority: registryAuthority,
|
|
54
|
+
owner: parsed.owner,
|
|
55
|
+
name: parsed.name,
|
|
56
|
+
})
|
|
57
|
+
: `${parsed.owner}/${parsed.type}/${parsed.name}`,
|
|
40
58
|
...(parsed.versionRange === undefined ? {} : { constraint: parsed.versionRange }),
|
|
41
59
|
};
|
|
42
60
|
}
|
|
@@ -83,6 +101,7 @@ export const collectDesiredConstraintContributors = (_path, origins) => origins
|
|
|
83
101
|
source: "settings",
|
|
84
102
|
range: origin.constraint,
|
|
85
103
|
location: SETTINGS_FILENAME,
|
|
104
|
+
...(origin.localName === undefined ? {} : { localName: origin.localName }),
|
|
86
105
|
},
|
|
87
106
|
];
|
|
88
107
|
}
|
|
@@ -113,7 +132,7 @@ const parsePackManifest = (raw) => {
|
|
|
113
132
|
const decoded = Schema.decodeUnknownResult(PackManifestSchema)(parsed);
|
|
114
133
|
return Result.isSuccess(decoded) ? decoded.success : undefined;
|
|
115
134
|
};
|
|
116
|
-
export const buildDesiredStateGraph = ({ baseDir, settings, layout, prospectivePacks = [], }) => Effect.gen(function* () {
|
|
135
|
+
export const buildDesiredStateGraph = ({ baseDir, settings, layout, prospectivePacks = [], registryAuthorities = {}, }) => Effect.gen(function* () {
|
|
117
136
|
const fs = yield* FileSystem.FileSystem;
|
|
118
137
|
const path = yield* Path.Path;
|
|
119
138
|
const candidates = [];
|
|
@@ -124,7 +143,7 @@ export const buildDesiredStateGraph = ({ baseDir, settings, layout, prospectiveP
|
|
|
124
143
|
const bundled = type === "skill" && entry.origin === "bundled";
|
|
125
144
|
const identity = bundled
|
|
126
145
|
? { identity: `bundled:@agentxm/skills/${name}` }
|
|
127
|
-
: sourceIdentity(type, name, entry.source, settings);
|
|
146
|
+
: sourceIdentity(type, name, entry.source, settings, registryAuthorities);
|
|
128
147
|
if (!bundled && isWorkspaceSourceLocator(entry.source) && settings.owner === undefined) {
|
|
129
148
|
problems.push({ type: "workspace-owner-missing", extensionType: type, name });
|
|
130
149
|
}
|
|
@@ -138,6 +157,7 @@ export const buildDesiredStateGraph = ({ baseDir, settings, layout, prospectiveP
|
|
|
138
157
|
...(identity.constraint === undefined ? {} : { constraint: identity.constraint }),
|
|
139
158
|
origin: {
|
|
140
159
|
type: "settings",
|
|
160
|
+
localName: name,
|
|
141
161
|
authority: "sourced",
|
|
142
162
|
source: entry.source,
|
|
143
163
|
enabled: entry.enabled,
|
|
@@ -155,11 +175,16 @@ export const buildDesiredStateGraph = ({ baseDir, settings, layout, prospectiveP
|
|
|
155
175
|
identity: `@workspace/mcps/${name}`,
|
|
156
176
|
authority: "inline",
|
|
157
177
|
enabled: entry.enabled,
|
|
158
|
-
origin: {
|
|
178
|
+
origin: {
|
|
179
|
+
type: "settings",
|
|
180
|
+
localName: name,
|
|
181
|
+
authority: "inline",
|
|
182
|
+
enabled: entry.enabled,
|
|
183
|
+
},
|
|
159
184
|
});
|
|
160
185
|
continue;
|
|
161
186
|
}
|
|
162
|
-
const identity = sourceIdentity("mcp-server", name, entry.source, settings);
|
|
187
|
+
const identity = sourceIdentity("mcp-server", name, entry.source, settings, registryAuthorities);
|
|
163
188
|
if (isWorkspaceSourceLocator(entry.source) && settings.owner === undefined) {
|
|
164
189
|
problems.push({ type: "workspace-owner-missing", extensionType: "mcp-server", name });
|
|
165
190
|
}
|
|
@@ -173,6 +198,7 @@ export const buildDesiredStateGraph = ({ baseDir, settings, layout, prospectiveP
|
|
|
173
198
|
...(identity.constraint === undefined ? {} : { constraint: identity.constraint }),
|
|
174
199
|
origin: {
|
|
175
200
|
type: "settings",
|
|
201
|
+
localName: name,
|
|
176
202
|
authority: "sourced",
|
|
177
203
|
source: entry.source,
|
|
178
204
|
enabled: entry.enabled,
|
|
@@ -207,6 +233,7 @@ export const buildDesiredStateGraph = ({ baseDir, settings, layout, prospectiveP
|
|
|
207
233
|
...(identity.constraint === undefined ? {} : { constraint: identity.constraint }),
|
|
208
234
|
origin: {
|
|
209
235
|
type: "settings",
|
|
236
|
+
localName: identity.name,
|
|
210
237
|
authority: "sourced",
|
|
211
238
|
source: entry.source,
|
|
212
239
|
enabled: entry.enabled !== false,
|
|
@@ -267,10 +294,18 @@ export const buildDesiredStateGraph = ({ baseDir, settings, layout, prospectiveP
|
|
|
267
294
|
const parsed = parseExtensionFqnParts(fqn);
|
|
268
295
|
if (parsed === undefined || parsed.type === "pack")
|
|
269
296
|
continue;
|
|
297
|
+
const dependencyIdentity = parsed.type === "mcp-server" &&
|
|
298
|
+
registryAuthorities[configuredRegistrySource] !== undefined
|
|
299
|
+
? mcpRegistryResolutionKey({
|
|
300
|
+
authority: registryAuthorities[configuredRegistrySource],
|
|
301
|
+
owner: parsed.owner,
|
|
302
|
+
name: parsed.name,
|
|
303
|
+
})
|
|
304
|
+
: `${parsed.owner}/${toExtensionTypePlural(parsed.type)}/${parsed.name}`;
|
|
270
305
|
candidates.push({
|
|
271
306
|
type: parsed.type,
|
|
272
307
|
name: parsed.name,
|
|
273
|
-
identity:
|
|
308
|
+
identity: dependencyIdentity,
|
|
274
309
|
authority: "sourced",
|
|
275
310
|
source: `${fqn}@${constraint}`,
|
|
276
311
|
enabled: entry.enabled !== false,
|
|
@@ -344,7 +379,21 @@ export const buildDesiredStateGraph = ({ baseDir, settings, layout, prospectiveP
|
|
|
344
379
|
origins,
|
|
345
380
|
});
|
|
346
381
|
}
|
|
382
|
+
const mcpClosuresByIdentity = new Map();
|
|
347
383
|
for (const node of nodes.values()) {
|
|
384
|
+
if (node.type === "mcp-server" && isSourcedDesiredExtension(node)) {
|
|
385
|
+
const existing = mcpClosuresByIdentity.get(node.identity);
|
|
386
|
+
mcpClosuresByIdentity.set(node.identity, {
|
|
387
|
+
identity: node.identity,
|
|
388
|
+
localNames: [...(existing?.localNames ?? []), node.name].sort(),
|
|
389
|
+
constraints: [
|
|
390
|
+
...(existing?.constraints ?? []),
|
|
391
|
+
...node.constraints.filter((constraint) => !(existing?.constraints ?? []).includes(constraint)),
|
|
392
|
+
],
|
|
393
|
+
origins: [...(existing?.origins ?? []), ...node.origins],
|
|
394
|
+
});
|
|
395
|
+
continue;
|
|
396
|
+
}
|
|
348
397
|
if (intersectVersionConstraints(node.constraints) === undefined) {
|
|
349
398
|
problems.push({
|
|
350
399
|
type: "constraint-conflict",
|
|
@@ -355,16 +404,36 @@ export const buildDesiredStateGraph = ({ baseDir, settings, layout, prospectiveP
|
|
|
355
404
|
});
|
|
356
405
|
}
|
|
357
406
|
}
|
|
407
|
+
const mcpSourceClosures = [...mcpClosuresByIdentity.values()].sort((left, right) => left.identity.localeCompare(right.identity));
|
|
408
|
+
for (const closure of mcpSourceClosures) {
|
|
409
|
+
if (intersectVersionConstraints(closure.constraints) === undefined) {
|
|
410
|
+
problems.push({
|
|
411
|
+
type: "constraint-conflict",
|
|
412
|
+
extensionType: "mcp-server",
|
|
413
|
+
name: closure.localNames.join(", "),
|
|
414
|
+
constraints: closure.constraints,
|
|
415
|
+
contributors: collectDesiredConstraintContributors(path, closure.origins),
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
}
|
|
358
419
|
const typeOrder = new Map(extensionTypes.map((type, index) => [type, index]));
|
|
359
420
|
const orderedNodes = [...nodes.values()]
|
|
360
421
|
.map((node) => {
|
|
361
422
|
if (isInlineDesiredExtension(node))
|
|
362
423
|
return node;
|
|
363
|
-
const
|
|
424
|
+
const constraints = node.type === "mcp-server"
|
|
425
|
+
? (mcpClosuresByIdentity.get(node.identity)?.constraints ?? node.constraints)
|
|
426
|
+
: node.constraints;
|
|
427
|
+
const constraint = intersectVersionConstraints(constraints);
|
|
364
428
|
return {
|
|
365
429
|
...node,
|
|
366
|
-
|
|
367
|
-
|
|
430
|
+
constraints,
|
|
431
|
+
source: constraints.length > 0 && constraint !== undefined
|
|
432
|
+
? node.type === "mcp-server"
|
|
433
|
+
? withVersionConstraint(node.source, constraint)
|
|
434
|
+
: node.identity.startsWith("@")
|
|
435
|
+
? `${node.identity}@${constraint}`
|
|
436
|
+
: node.source
|
|
368
437
|
: node.source,
|
|
369
438
|
};
|
|
370
439
|
})
|
|
@@ -378,6 +447,7 @@ export const buildDesiredStateGraph = ({ baseDir, settings, layout, prospectiveP
|
|
|
378
447
|
return {
|
|
379
448
|
complete: problems.length === 0,
|
|
380
449
|
nodes: orderedNodes,
|
|
450
|
+
mcpSourceClosures,
|
|
381
451
|
problems,
|
|
382
452
|
};
|
|
383
453
|
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical identity for one accepted MCP source-resolution closure.
|
|
3
|
+
*
|
|
4
|
+
* Connection names deliberately do not participate: several local MCP
|
|
5
|
+
* connections may share this identity and therefore one accepted resolution.
|
|
6
|
+
*/
|
|
7
|
+
import type { Handle } from "@agentxm/extension-model/unstable/extensions/handle";
|
|
8
|
+
import type { ExtensionName } from "@agentxm/extension-model/unstable/extensions/common";
|
|
9
|
+
import type { McpServerLockEntry } from "../lockfile/schema.js";
|
|
10
|
+
export declare const mcpRegistryResolutionKey: (args: {
|
|
11
|
+
readonly authority: URL | string;
|
|
12
|
+
readonly owner: Handle | string;
|
|
13
|
+
readonly name: ExtensionName | string;
|
|
14
|
+
}) => string;
|
|
15
|
+
/** Deterministic lock-map key for every currently accepted MCP source class. */
|
|
16
|
+
export declare const mcpResolutionKey: (entry: McpServerLockEntry) => string;
|
|
17
|
+
//# sourceMappingURL=mcp-source-identity.d.ts.map
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical identity for one accepted MCP source-resolution closure.
|
|
3
|
+
*
|
|
4
|
+
* Connection names deliberately do not participate: several local MCP
|
|
5
|
+
* connections may share this identity and therefore one accepted resolution.
|
|
6
|
+
*/
|
|
7
|
+
const normalizeAuthority = (authority) => {
|
|
8
|
+
const raw = authority instanceof URL ? authority.href : authority;
|
|
9
|
+
try {
|
|
10
|
+
const normalized = new URL(raw).href;
|
|
11
|
+
return normalized.endsWith("/") ? normalized.slice(0, -1) : normalized;
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return raw.endsWith("/") ? raw.slice(0, -1) : raw;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
const encodeIdentityPart = (value) => encodeURIComponent(value);
|
|
18
|
+
export const mcpRegistryResolutionKey = (args) => `registry:${encodeIdentityPart(normalizeAuthority(args.authority))}:${args.owner}/mcps/${args.name}`;
|
|
19
|
+
/** Deterministic lock-map key for every currently accepted MCP source class. */
|
|
20
|
+
export const mcpResolutionKey = (entry) => {
|
|
21
|
+
switch (entry.type) {
|
|
22
|
+
case "registry":
|
|
23
|
+
return mcpRegistryResolutionKey({
|
|
24
|
+
authority: entry.endpoint,
|
|
25
|
+
owner: entry.owner,
|
|
26
|
+
name: entry.name,
|
|
27
|
+
});
|
|
28
|
+
case "github":
|
|
29
|
+
case "gitlab":
|
|
30
|
+
case "bitbucket":
|
|
31
|
+
return `${entry.type}:${encodeIdentityPart(normalizeAuthority(entry.endpoint))}:${entry.owner}/${entry.repo}:${entry.packageOwner ?? ""}/mcps/${entry.packageName}`;
|
|
32
|
+
case "azurerepos":
|
|
33
|
+
return `azurerepos:${encodeIdentityPart(normalizeAuthority(entry.endpoint))}:${entry.organization}/${entry.project}/${entry.repo}:${entry.packageOwner ?? ""}/mcps/${entry.packageName}`;
|
|
34
|
+
case "git":
|
|
35
|
+
return `git:${encodeIdentityPart(normalizeAuthority(entry.url))}:${entry.packageOwner ?? ""}/mcps/${entry.packageName}`;
|
|
36
|
+
case "local":
|
|
37
|
+
return `local:${encodeIdentityPart(entry.path)}:${entry.packageOwner ?? ""}/mcps/${entry.packageName}`;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
//# sourceMappingURL=mcp-source-identity.js.map
|
|
@@ -362,7 +362,7 @@ const validSettingsContents = {
|
|
|
362
362
|
skills: { "managed-tool": { source: "github:owner/repo", enabled: true } },
|
|
363
363
|
};
|
|
364
364
|
const validLockfileContents = {
|
|
365
|
-
lockfileVersion:
|
|
365
|
+
lockfileVersion: 7,
|
|
366
366
|
skills: {
|
|
367
367
|
"managed-tool": {
|
|
368
368
|
type: "github",
|
|
@@ -59,8 +59,18 @@ export declare class LockfileDecodeError extends LockfileDecodeError_base<{
|
|
|
59
59
|
readonly raw: unknown;
|
|
60
60
|
}> {
|
|
61
61
|
}
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
declare const LockfileVersionUnsupported_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
63
|
+
readonly _tag: "LockfileVersionUnsupported";
|
|
64
|
+
} & Readonly<A>;
|
|
65
|
+
/** A syntactically valid lockfile declares a version this CLI cannot read. */
|
|
66
|
+
export declare class LockfileVersionUnsupported extends LockfileVersionUnsupported_base<{
|
|
67
|
+
readonly path: string;
|
|
68
|
+
readonly observedVersion: number;
|
|
69
|
+
readonly supportedVersion: number;
|
|
70
|
+
}> {
|
|
71
|
+
}
|
|
72
|
+
/** Lockfile-read failure union (IO, parse, decode, unsupported version). */
|
|
73
|
+
export type LockfileReadError = LockfileIoError | LockfileParseError | LockfileDecodeError | LockfileVersionUnsupported;
|
|
64
74
|
declare const WorkspaceRootEscape_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
65
75
|
readonly _tag: "WorkspaceRootEscape";
|
|
66
76
|
} & Readonly<A>;
|
|
@@ -18,6 +18,9 @@ export class LockfileParseError extends Data.TaggedError("LockfileParseError") {
|
|
|
18
18
|
/** Lockfile schema decode failure; `raw` carries the parsed value. */
|
|
19
19
|
export class LockfileDecodeError extends Data.TaggedError("LockfileDecodeError") {
|
|
20
20
|
}
|
|
21
|
+
/** A syntactically valid lockfile declares a version this CLI cannot read. */
|
|
22
|
+
export class LockfileVersionUnsupported extends Data.TaggedError("LockfileVersionUnsupported") {
|
|
23
|
+
}
|
|
21
24
|
/** Provider-construction error: workspace root escapes the configured allowed root. */
|
|
22
25
|
export class WorkspaceRootEscape extends Data.TaggedError("WorkspaceRootEscape") {
|
|
23
26
|
}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import * as Effect from "effect/Effect";
|
|
11
11
|
import * as Option from "effect/Option";
|
|
12
12
|
import { decodeExtensionNameSync, } from "@agentxm/extension-model/unstable/extensions/common";
|
|
13
|
+
import { parseSourceQualifiedRegistrySourcePatternParts } from "@agentxm/extension-model/unstable/extensions";
|
|
13
14
|
import { filterMapOccurrences } from "./actual-helpers.js";
|
|
14
15
|
import { canonicalAxmPackageRoot } from "./package-root.js";
|
|
15
16
|
import { makeProjectedSubjectCells, projectInstalledExtensions, } from "./projection.js";
|
|
@@ -24,18 +25,39 @@ const declaredFromSettings = (settings) => {
|
|
|
24
25
|
entry,
|
|
25
26
|
}));
|
|
26
27
|
};
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
28
|
+
const resolvedFromState = (settings, lockfile, packs) => {
|
|
29
|
+
const locked = Object.values(lockfile.mcpServers ?? {});
|
|
30
|
+
const resolved = [];
|
|
31
|
+
const names = new Set();
|
|
32
|
+
for (const [localName, entry] of Object.entries(settings.mcpServers ?? {})) {
|
|
33
|
+
if (entry.kind === "inline")
|
|
34
|
+
continue;
|
|
35
|
+
const parsed = parseSourceQualifiedRegistrySourcePatternParts(entry.source);
|
|
36
|
+
const lockEntry = locked.find((candidate) => parsed !== undefined && candidate.type === "registry"
|
|
37
|
+
? candidate.sourceName === parsed.sourceName &&
|
|
38
|
+
candidate.owner === parsed.owner &&
|
|
39
|
+
candidate.name === parsed.name
|
|
40
|
+
: candidate.workspaceName === localName);
|
|
41
|
+
if (lockEntry === undefined)
|
|
42
|
+
continue;
|
|
43
|
+
names.add(localName);
|
|
44
|
+
resolved.push({ name: decodeExtensionNameSync(localName), lockEntry });
|
|
45
|
+
}
|
|
46
|
+
for (const member of packs.flatMap((pack) => pack.mcpServers)) {
|
|
47
|
+
if (names.has(member.name))
|
|
48
|
+
continue;
|
|
49
|
+
const lockEntry = locked.find((candidate) => candidate.workspaceName === member.name);
|
|
50
|
+
if (lockEntry === undefined)
|
|
51
|
+
continue;
|
|
52
|
+
names.add(member.name);
|
|
53
|
+
resolved.push({ name: member.name, lockEntry });
|
|
54
|
+
}
|
|
55
|
+
return resolved;
|
|
34
56
|
};
|
|
35
|
-
const canonicalToActual = (occ, scope) => {
|
|
57
|
+
const canonicalToActual = (occ, scope, localName = occ.name) => {
|
|
36
58
|
const packageRoot = canonicalAxmPackageRoot(occ);
|
|
37
59
|
return {
|
|
38
|
-
key: { scope, type: "mcp-server", name:
|
|
60
|
+
key: { scope, type: "mcp-server", name: localName },
|
|
39
61
|
origin: occ.origin === "canonical-axm"
|
|
40
62
|
? { _tag: "canonical-axm-mcp-server" }
|
|
41
63
|
: { _tag: "external-axm-mcp-server" },
|
|
@@ -94,11 +116,24 @@ const mcpServerPolicy = (scope) => ({
|
|
|
94
116
|
export const makeMcpServerExtensionsApi = (deps) => Effect.gen(function* () {
|
|
95
117
|
const { scope, loaders, scanners, installedPacks, diagnostics } = deps;
|
|
96
118
|
const declared = loaders.settings.pipe(Effect.map((opt) => Option.map(opt, declaredFromSettings)));
|
|
97
|
-
const resolved =
|
|
119
|
+
const resolved = Effect.all({
|
|
120
|
+
settings: loaders.settings.pipe(Effect.catch(() => Effect.succeed(Option.none()))),
|
|
121
|
+
lockfile: loaders.lockfile,
|
|
122
|
+
packs: installedPacks.pipe(Effect.catch(() => Effect.succeed([]))),
|
|
123
|
+
}).pipe(Effect.map(({ settings, lockfile, packs }) => Option.all({ settings, lockfile }).pipe(Option.map(({ settings: decodedSettings, lockfile: decodedLockfile }) => resolvedFromState(decodedSettings, decodedLockfile, packs)))));
|
|
98
124
|
const actual = Effect.gen(function* () {
|
|
99
125
|
const canonical = yield* scanners.canonical;
|
|
100
126
|
const mcpConfig = yield* scanners.mcpConfig;
|
|
101
|
-
const
|
|
127
|
+
const accepted = yield* resolved.pipe(Effect.catch(() => Effect.succeed(Option.none())));
|
|
128
|
+
const resolvedEntries = Option.getOrElse(accepted, () => []);
|
|
129
|
+
const fromCanonical = filterMapOccurrences(canonical, "mcp-server", (occ) => occ).flatMap((occ) => {
|
|
130
|
+
const matchingNames = resolvedEntries
|
|
131
|
+
.filter((entry) => entry.lockEntry.type === "registry" && entry.lockEntry.name === occ.name)
|
|
132
|
+
.map((entry) => entry.name);
|
|
133
|
+
return matchingNames.length === 0
|
|
134
|
+
? [canonicalToActual(occ, scope)]
|
|
135
|
+
: matchingNames.map((name) => canonicalToActual(occ, scope, name));
|
|
136
|
+
});
|
|
102
137
|
const fromMcpConfig = mcpConfig.map((occ) => mcpConfigToActual(occ, scope));
|
|
103
138
|
return [...fromCanonical, ...fromMcpConfig];
|
|
104
139
|
});
|
|
@@ -3,10 +3,10 @@ import * as Effect from "effect/Effect";
|
|
|
3
3
|
import * as Option from "effect/Option";
|
|
4
4
|
import * as Schema from "effect/Schema";
|
|
5
5
|
import YAML from "yaml";
|
|
6
|
-
import { LockfileSchema } from "../../lockfile/schema.js";
|
|
6
|
+
import { LOCKFILE_VERSION, LockfileSchema } from "../../lockfile/schema.js";
|
|
7
7
|
import { formatSchemaIssuesToLines } from "@agentxm/extension-model/unstable/schema-issues";
|
|
8
8
|
import { SettingsSchema } from "../../settings/schema.js";
|
|
9
|
-
import { LockfileDecodeError, LockfileIoError, LockfileParseError, SettingsDecodeError, SettingsIoError, SettingsParseError, } from "./errors.js";
|
|
9
|
+
import { LockfileDecodeError, LockfileIoError, LockfileParseError, LockfileVersionUnsupported, SettingsDecodeError, SettingsIoError, SettingsParseError, } from "./errors.js";
|
|
10
10
|
// ---------------------------------------------------------------------------
|
|
11
11
|
// Raw bytes loaders (shared by the decoded loaders and the public raw cells)
|
|
12
12
|
// ---------------------------------------------------------------------------
|
|
@@ -71,6 +71,22 @@ const loadLockfile = (rawCell) => Effect.gen(function* () {
|
|
|
71
71
|
try: () => YAML.parse(bytes),
|
|
72
72
|
catch: (cause) => new LockfileParseError({ path, raw: bytes, cause }),
|
|
73
73
|
});
|
|
74
|
+
if (typeof parsed === "object" &&
|
|
75
|
+
parsed !== null &&
|
|
76
|
+
!Array.isArray(parsed) &&
|
|
77
|
+
Object.hasOwn(parsed, "lockfileVersion")) {
|
|
78
|
+
const observedVersion = Reflect.get(parsed, "lockfileVersion");
|
|
79
|
+
if (typeof observedVersion === "number" &&
|
|
80
|
+
Number.isSafeInteger(observedVersion) &&
|
|
81
|
+
observedVersion > 0 &&
|
|
82
|
+
observedVersion !== LOCKFILE_VERSION) {
|
|
83
|
+
return yield* Effect.fail(new LockfileVersionUnsupported({
|
|
84
|
+
path,
|
|
85
|
+
observedVersion,
|
|
86
|
+
supportedVersion: LOCKFILE_VERSION,
|
|
87
|
+
}));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
74
90
|
const decoded = yield* Schema.decodeUnknownEffect(LockfileSchema)(parsed).pipe(Effect.mapError((error) => new LockfileDecodeError({
|
|
75
91
|
path,
|
|
76
92
|
issues: formatSchemaIssuesToLines(error.issue),
|
|
@@ -63,7 +63,7 @@ export interface InstalledPackRef {
|
|
|
63
63
|
*
|
|
64
64
|
* The failure channels are intentionally narrow: `declared` only fails with
|
|
65
65
|
* `SettingsReadError` (3 tags), `resolved` only fails with
|
|
66
|
-
* `LockfileReadError` (
|
|
66
|
+
* `LockfileReadError` (4 tags), and `actual` never fails — workspace-root
|
|
67
67
|
* path-escape is validated once at provider construction (Layer-level), not
|
|
68
68
|
* per cell.
|
|
69
69
|
*/
|
|
@@ -212,6 +212,8 @@ export interface SetSubagentArgs {
|
|
|
212
212
|
*/
|
|
213
213
|
export interface SetMcpServerArgs {
|
|
214
214
|
readonly name: string;
|
|
215
|
+
/** Canonical source-resolution key. Unlike name, this is not connection-scoped. */
|
|
216
|
+
readonly resolutionKey: string;
|
|
215
217
|
readonly lockEntry: McpServerLockEntry;
|
|
216
218
|
readonly versionRange: Option.Option<string>;
|
|
217
219
|
readonly env?: Readonly<Record<string, string>>;
|
|
@@ -408,8 +410,10 @@ export interface WorkspaceMutationsService {
|
|
|
408
410
|
readonly removeSubagentLock: (name: string) => Effect.Effect<void, WorkspaceLockfileMutationFailure>;
|
|
409
411
|
/** Read lockfile and return the MCP servers lock map. */
|
|
410
412
|
readonly getLockedMcpServers: () => Effect.Effect<McpServersLockMap, WorkspaceLockfileReadFailure>;
|
|
411
|
-
/** Read lockfile and return
|
|
412
|
-
readonly getLockedMcpServer: (
|
|
413
|
+
/** Read lockfile and return an MCP accepted resolution by source-resolution identity. */
|
|
414
|
+
readonly getLockedMcpServer: (resolutionKey: string) => Effect.Effect<Option.Option<McpServerLockEntry>, WorkspaceLockfileReadFailure>;
|
|
415
|
+
/** Resolve a local MCP connection name to its shared accepted resolution. */
|
|
416
|
+
readonly getLockedMcpServerForConnection: (localName: string) => Effect.Effect<Option.Option<McpServerLockEntry>, WorkspaceStateReadFailure>;
|
|
413
417
|
/** Update desired MCP settings and any external accepted resolution atomically. */
|
|
414
418
|
readonly setMcpServer: (args: SetMcpServerArgs) => Effect.Effect<void, WorkspaceStateMutationFailure>;
|
|
415
419
|
/** Add or update an MCP server in lockfile only (skip settings). Used for pack dependencies. Serialized by semaphore. */
|
|
@@ -469,11 +473,11 @@ export interface WorkspaceMutationsOptions {
|
|
|
469
473
|
readonly allowUninitialized?: boolean;
|
|
470
474
|
}
|
|
471
475
|
/**
|
|
472
|
-
* Error loading workspace mutations: scoped settings reads,
|
|
473
|
-
* resolution, and the initialization gate.
|
|
476
|
+
* Error loading workspace mutations: scoped settings and lockfile reads,
|
|
477
|
+
* layout resolution, and the initialization gate.
|
|
474
478
|
*
|
|
475
479
|
* @experimental This API is unstable and may change without notice.
|
|
476
480
|
*/
|
|
477
|
-
export type WorkspaceMutationsError = WorkspaceSettingsReadFailure | WorkspaceLayoutError | WorkspaceNotInitialized;
|
|
481
|
+
export type WorkspaceMutationsError = WorkspaceSettingsReadFailure | WorkspaceLockfileReadFailure | WorkspaceLayoutError | WorkspaceNotInitialized;
|
|
478
482
|
export {};
|
|
479
483
|
//# sourceMappingURL=service-interface.d.ts.map
|
|
@@ -22,6 +22,7 @@ import * as Path from "effect/Path";
|
|
|
22
22
|
import * as Option from "effect/Option";
|
|
23
23
|
import type { Handle } from "@agentxm/extension-model/unstable/extensions/handle";
|
|
24
24
|
import { DesiredPackGraphIncomplete, InvalidAgentId, LockedSkillMissing, SettingsEntryMissing, WorkspaceNotInitialized } from "./errors.js";
|
|
25
|
+
import { LockfileVersionUnsupported } from "./read-model/errors.js";
|
|
25
26
|
import { LockfileValidationError } from "../lockfile/errors.js";
|
|
26
27
|
import { type HookEntry, type KnowledgeEntry, type InstructionsConfigValue, type McpServerEntry, type SkillEntry, type SubagentEntry, type PackEntry, type RuleEntry, type SourceHostConfig } from "../settings/index.js";
|
|
27
28
|
import { type ScopedReleaseAgeExcludePattern } from "@agentxm/extension-model/unstable/extensions/release-age";
|
|
@@ -36,8 +37,9 @@ export type WorkspaceLayerOptions = WorkspaceMutationsOptions;
|
|
|
36
37
|
/**
|
|
37
38
|
* Create the workspace mutations service from an existing workspace on disk.
|
|
38
39
|
*
|
|
39
|
-
* The workspace must already be initialized. Missing or invalid settings
|
|
40
|
-
* fast with a typed
|
|
40
|
+
* The workspace must already be initialized. Missing or invalid settings and
|
|
41
|
+
* invalid or unsupported lockfiles fail fast with a typed
|
|
42
|
+
* `WorkspaceMutationsError`. The two operations-side
|
|
41
43
|
* capabilities — the transaction runner and transition acquirer — are
|
|
42
44
|
* injected through `makeCapabilities`; the composition seam in
|
|
43
45
|
* `./operations/load-workspace.ts` supplies the live implementation.
|
|
@@ -52,7 +54,7 @@ export declare const makeWorkspaceMutations: (options: WorkspaceLayerOptions, ma
|
|
|
52
54
|
getLockfileState: () => Effect.Effect<LockfileState, LockfileValidationError | WorkspaceRootEscape>;
|
|
53
55
|
getDesiredStateGraph: (graphOptions?: Parameters<(graphOptions?: {
|
|
54
56
|
readonly prospectivePacks?: Parameters<typeof buildDesiredStateGraph>[0]["prospectivePacks"];
|
|
55
|
-
}) => Effect.Effect<import("./desired-state-graph.js").DesiredStateGraph,
|
|
57
|
+
}) => Effect.Effect<import("./desired-state-graph.js").DesiredStateGraph, import("./read-model/errors.js").SettingsIoError | import("./read-model/errors.js").SettingsParseError | import("./read-model/errors.js").SettingsDecodeError | import("./read-model/errors.js").LockfileIoError | import("./read-model/errors.js").LockfileParseError | import("./read-model/errors.js").LockfileDecodeError | LockfileVersionUnsupported | WorkspaceRootEscape, never>>[0]) => Effect.Effect<import("./desired-state-graph.js").DesiredStateGraph, import("./read-model/errors.js").SettingsIoError | import("./read-model/errors.js").SettingsParseError | import("./read-model/errors.js").SettingsDecodeError | import("./read-model/errors.js").LockfileIoError | import("./read-model/errors.js").LockfileParseError | import("./read-model/errors.js").LockfileDecodeError | LockfileVersionUnsupported | WorkspaceRootEscape, never>;
|
|
56
58
|
getConfiguredSources: () => Effect.Effect<ReadonlyArray<SourceHostConfig>, WorkspaceSettingsReadFailure>;
|
|
57
59
|
getConfiguredSourceByName: (name: string) => Effect.Effect<Option.Option<{
|
|
58
60
|
readonly name: string;
|
|
@@ -1534,7 +1536,7 @@ export declare const makeWorkspaceMutations: (options: WorkspaceLayerOptions, ma
|
|
|
1534
1536
|
readonly treeIntegrity: string & import("effect/Brand").Brand<"TreeIntegrity">;
|
|
1535
1537
|
};
|
|
1536
1538
|
}, LockfileReadError | WorkspaceRootEscape, never>;
|
|
1537
|
-
getLockedMcpServer: (
|
|
1539
|
+
getLockedMcpServer: (resolutionKey: string) => Effect.Effect<Option.Option<{
|
|
1538
1540
|
readonly type: "github";
|
|
1539
1541
|
readonly owner: string;
|
|
1540
1542
|
readonly sourceType: "github";
|
|
@@ -1650,8 +1652,239 @@ export declare const makeWorkspaceMutations: (options: WorkspaceLayerOptions, ma
|
|
|
1650
1652
|
readonly publisherBindingId: string;
|
|
1651
1653
|
readonly treeIntegrity: string & import("effect/Brand").Brand<"TreeIntegrity">;
|
|
1652
1654
|
}>, LockfileReadError | WorkspaceRootEscape, never>;
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
+
getLockedMcpServerForConnection: (localName: string) => Effect.Effect<Option.None<{
|
|
1656
|
+
readonly type: "github";
|
|
1657
|
+
readonly owner: string;
|
|
1658
|
+
readonly sourceType: "github";
|
|
1659
|
+
readonly extensionType: "mcp-server";
|
|
1660
|
+
readonly sourceName: string;
|
|
1661
|
+
readonly packageFormat: "agentxm";
|
|
1662
|
+
readonly endpoint: URL;
|
|
1663
|
+
readonly workspaceName: string & import("effect/Brand").Brand<"ExtensionName">;
|
|
1664
|
+
readonly packageOwner: string & import("effect/Brand").Brand<"Handle">;
|
|
1665
|
+
readonly packageName: string & import("effect/Brand").Brand<"ExtensionName">;
|
|
1666
|
+
readonly repo: string;
|
|
1667
|
+
readonly resolvedCommit: string;
|
|
1668
|
+
readonly resolvedTree: string;
|
|
1669
|
+
readonly contentIdentity: string & import("effect/Brand").Brand<"SourceHash">;
|
|
1670
|
+
readonly treeIntegrity: string & import("effect/Brand").Brand<"TreeIntegrity">;
|
|
1671
|
+
readonly path?: string | undefined;
|
|
1672
|
+
readonly ref?: string | undefined;
|
|
1673
|
+
} | {
|
|
1674
|
+
readonly type: "gitlab";
|
|
1675
|
+
readonly owner: string;
|
|
1676
|
+
readonly sourceType: "gitlab";
|
|
1677
|
+
readonly extensionType: "mcp-server";
|
|
1678
|
+
readonly sourceName: string;
|
|
1679
|
+
readonly packageFormat: "agentxm";
|
|
1680
|
+
readonly endpoint: URL;
|
|
1681
|
+
readonly workspaceName: string & import("effect/Brand").Brand<"ExtensionName">;
|
|
1682
|
+
readonly packageOwner: string & import("effect/Brand").Brand<"Handle">;
|
|
1683
|
+
readonly packageName: string & import("effect/Brand").Brand<"ExtensionName">;
|
|
1684
|
+
readonly repo: string;
|
|
1685
|
+
readonly resolvedCommit: string;
|
|
1686
|
+
readonly resolvedTree: string;
|
|
1687
|
+
readonly contentIdentity: string & import("effect/Brand").Brand<"SourceHash">;
|
|
1688
|
+
readonly treeIntegrity: string & import("effect/Brand").Brand<"TreeIntegrity">;
|
|
1689
|
+
readonly path?: string | undefined;
|
|
1690
|
+
readonly ref?: string | undefined;
|
|
1691
|
+
} | {
|
|
1692
|
+
readonly type: "bitbucket";
|
|
1693
|
+
readonly owner: string;
|
|
1694
|
+
readonly sourceType: "bitbucket";
|
|
1695
|
+
readonly extensionType: "mcp-server";
|
|
1696
|
+
readonly sourceName: string;
|
|
1697
|
+
readonly packageFormat: "agentxm";
|
|
1698
|
+
readonly endpoint: URL;
|
|
1699
|
+
readonly workspaceName: string & import("effect/Brand").Brand<"ExtensionName">;
|
|
1700
|
+
readonly packageOwner: string & import("effect/Brand").Brand<"Handle">;
|
|
1701
|
+
readonly packageName: string & import("effect/Brand").Brand<"ExtensionName">;
|
|
1702
|
+
readonly repo: string;
|
|
1703
|
+
readonly resolvedCommit: string;
|
|
1704
|
+
readonly resolvedTree: string;
|
|
1705
|
+
readonly contentIdentity: string & import("effect/Brand").Brand<"SourceHash">;
|
|
1706
|
+
readonly treeIntegrity: string & import("effect/Brand").Brand<"TreeIntegrity">;
|
|
1707
|
+
readonly path?: string | undefined;
|
|
1708
|
+
readonly ref?: string | undefined;
|
|
1709
|
+
} | {
|
|
1710
|
+
readonly type: "azurerepos";
|
|
1711
|
+
readonly sourceType: "azurerepos";
|
|
1712
|
+
readonly extensionType: "mcp-server";
|
|
1713
|
+
readonly sourceName: string;
|
|
1714
|
+
readonly packageFormat: "agentxm";
|
|
1715
|
+
readonly endpoint: URL;
|
|
1716
|
+
readonly workspaceName: string & import("effect/Brand").Brand<"ExtensionName">;
|
|
1717
|
+
readonly packageOwner: string & import("effect/Brand").Brand<"Handle">;
|
|
1718
|
+
readonly packageName: string & import("effect/Brand").Brand<"ExtensionName">;
|
|
1719
|
+
readonly repo: string;
|
|
1720
|
+
readonly resolvedCommit: string;
|
|
1721
|
+
readonly resolvedTree: string;
|
|
1722
|
+
readonly contentIdentity: string & import("effect/Brand").Brand<"SourceHash">;
|
|
1723
|
+
readonly treeIntegrity: string & import("effect/Brand").Brand<"TreeIntegrity">;
|
|
1724
|
+
readonly organization: string;
|
|
1725
|
+
readonly project: string;
|
|
1726
|
+
readonly path?: string | undefined;
|
|
1727
|
+
readonly ref?: string | undefined;
|
|
1728
|
+
} | {
|
|
1729
|
+
readonly type: "git";
|
|
1730
|
+
readonly url: string;
|
|
1731
|
+
readonly sourceType: "git";
|
|
1732
|
+
readonly extensionType: "mcp-server";
|
|
1733
|
+
readonly sourceName: "git";
|
|
1734
|
+
readonly packageFormat: "agentxm";
|
|
1735
|
+
readonly workspaceName: string & import("effect/Brand").Brand<"ExtensionName">;
|
|
1736
|
+
readonly packageOwner: string & import("effect/Brand").Brand<"Handle">;
|
|
1737
|
+
readonly packageName: string & import("effect/Brand").Brand<"ExtensionName">;
|
|
1738
|
+
readonly resolvedCommit: string;
|
|
1739
|
+
readonly resolvedTree: string;
|
|
1740
|
+
readonly contentIdentity: string & import("effect/Brand").Brand<"SourceHash">;
|
|
1741
|
+
readonly treeIntegrity: string & import("effect/Brand").Brand<"TreeIntegrity">;
|
|
1742
|
+
readonly path?: string | undefined;
|
|
1743
|
+
readonly ref?: string | undefined;
|
|
1744
|
+
} | {
|
|
1745
|
+
readonly type: "local";
|
|
1746
|
+
readonly sourceType: "local";
|
|
1747
|
+
readonly sourceName: "local";
|
|
1748
|
+
readonly extensionType: "mcp-server";
|
|
1749
|
+
readonly workspaceName: string & import("effect/Brand").Brand<"ExtensionName">;
|
|
1750
|
+
readonly packageFormat: "agentxm";
|
|
1751
|
+
readonly packageOwner: string & import("effect/Brand").Brand<"Handle">;
|
|
1752
|
+
readonly packageName: string & import("effect/Brand").Brand<"ExtensionName">;
|
|
1753
|
+
readonly path: string;
|
|
1754
|
+
readonly contentIdentity: string & import("effect/Brand").Brand<"SourceHash">;
|
|
1755
|
+
readonly treeIntegrity: string & import("effect/Brand").Brand<"TreeIntegrity">;
|
|
1756
|
+
} | {
|
|
1757
|
+
readonly type: "registry";
|
|
1758
|
+
readonly sourceType: "registry";
|
|
1759
|
+
readonly endpoint: URL;
|
|
1760
|
+
readonly extensionType: "mcp-server";
|
|
1761
|
+
readonly workspaceName: string & import("effect/Brand").Brand<"ExtensionName">;
|
|
1762
|
+
readonly packageFormat: "agentxm";
|
|
1763
|
+
readonly owner: string & import("effect/Brand").Brand<"Handle">;
|
|
1764
|
+
readonly name: string & import("effect/Brand").Brand<"ExtensionName">;
|
|
1765
|
+
readonly resolvedVersion: string & import("effect/Brand").Brand<"Version">;
|
|
1766
|
+
readonly integrity: string;
|
|
1767
|
+
readonly sourceName: string;
|
|
1768
|
+
readonly publisherBindingId: string;
|
|
1769
|
+
readonly treeIntegrity: string & import("effect/Brand").Brand<"TreeIntegrity">;
|
|
1770
|
+
}> | Option.Some<{
|
|
1771
|
+
readonly type: "github";
|
|
1772
|
+
readonly owner: string;
|
|
1773
|
+
readonly sourceType: "github";
|
|
1774
|
+
readonly extensionType: "mcp-server";
|
|
1775
|
+
readonly sourceName: string;
|
|
1776
|
+
readonly packageFormat: "agentxm";
|
|
1777
|
+
readonly endpoint: URL;
|
|
1778
|
+
readonly workspaceName: string & import("effect/Brand").Brand<"ExtensionName">;
|
|
1779
|
+
readonly packageOwner: string & import("effect/Brand").Brand<"Handle">;
|
|
1780
|
+
readonly packageName: string & import("effect/Brand").Brand<"ExtensionName">;
|
|
1781
|
+
readonly repo: string;
|
|
1782
|
+
readonly resolvedCommit: string;
|
|
1783
|
+
readonly resolvedTree: string;
|
|
1784
|
+
readonly contentIdentity: string & import("effect/Brand").Brand<"SourceHash">;
|
|
1785
|
+
readonly treeIntegrity: string & import("effect/Brand").Brand<"TreeIntegrity">;
|
|
1786
|
+
readonly path?: string | undefined;
|
|
1787
|
+
readonly ref?: string | undefined;
|
|
1788
|
+
} | {
|
|
1789
|
+
readonly type: "gitlab";
|
|
1790
|
+
readonly owner: string;
|
|
1791
|
+
readonly sourceType: "gitlab";
|
|
1792
|
+
readonly extensionType: "mcp-server";
|
|
1793
|
+
readonly sourceName: string;
|
|
1794
|
+
readonly packageFormat: "agentxm";
|
|
1795
|
+
readonly endpoint: URL;
|
|
1796
|
+
readonly workspaceName: string & import("effect/Brand").Brand<"ExtensionName">;
|
|
1797
|
+
readonly packageOwner: string & import("effect/Brand").Brand<"Handle">;
|
|
1798
|
+
readonly packageName: string & import("effect/Brand").Brand<"ExtensionName">;
|
|
1799
|
+
readonly repo: string;
|
|
1800
|
+
readonly resolvedCommit: string;
|
|
1801
|
+
readonly resolvedTree: string;
|
|
1802
|
+
readonly contentIdentity: string & import("effect/Brand").Brand<"SourceHash">;
|
|
1803
|
+
readonly treeIntegrity: string & import("effect/Brand").Brand<"TreeIntegrity">;
|
|
1804
|
+
readonly path?: string | undefined;
|
|
1805
|
+
readonly ref?: string | undefined;
|
|
1806
|
+
} | {
|
|
1807
|
+
readonly type: "bitbucket";
|
|
1808
|
+
readonly owner: string;
|
|
1809
|
+
readonly sourceType: "bitbucket";
|
|
1810
|
+
readonly extensionType: "mcp-server";
|
|
1811
|
+
readonly sourceName: string;
|
|
1812
|
+
readonly packageFormat: "agentxm";
|
|
1813
|
+
readonly endpoint: URL;
|
|
1814
|
+
readonly workspaceName: string & import("effect/Brand").Brand<"ExtensionName">;
|
|
1815
|
+
readonly packageOwner: string & import("effect/Brand").Brand<"Handle">;
|
|
1816
|
+
readonly packageName: string & import("effect/Brand").Brand<"ExtensionName">;
|
|
1817
|
+
readonly repo: string;
|
|
1818
|
+
readonly resolvedCommit: string;
|
|
1819
|
+
readonly resolvedTree: string;
|
|
1820
|
+
readonly contentIdentity: string & import("effect/Brand").Brand<"SourceHash">;
|
|
1821
|
+
readonly treeIntegrity: string & import("effect/Brand").Brand<"TreeIntegrity">;
|
|
1822
|
+
readonly path?: string | undefined;
|
|
1823
|
+
readonly ref?: string | undefined;
|
|
1824
|
+
} | {
|
|
1825
|
+
readonly type: "azurerepos";
|
|
1826
|
+
readonly sourceType: "azurerepos";
|
|
1827
|
+
readonly extensionType: "mcp-server";
|
|
1828
|
+
readonly sourceName: string;
|
|
1829
|
+
readonly packageFormat: "agentxm";
|
|
1830
|
+
readonly endpoint: URL;
|
|
1831
|
+
readonly workspaceName: string & import("effect/Brand").Brand<"ExtensionName">;
|
|
1832
|
+
readonly packageOwner: string & import("effect/Brand").Brand<"Handle">;
|
|
1833
|
+
readonly packageName: string & import("effect/Brand").Brand<"ExtensionName">;
|
|
1834
|
+
readonly repo: string;
|
|
1835
|
+
readonly resolvedCommit: string;
|
|
1836
|
+
readonly resolvedTree: string;
|
|
1837
|
+
readonly contentIdentity: string & import("effect/Brand").Brand<"SourceHash">;
|
|
1838
|
+
readonly treeIntegrity: string & import("effect/Brand").Brand<"TreeIntegrity">;
|
|
1839
|
+
readonly organization: string;
|
|
1840
|
+
readonly project: string;
|
|
1841
|
+
readonly path?: string | undefined;
|
|
1842
|
+
readonly ref?: string | undefined;
|
|
1843
|
+
} | {
|
|
1844
|
+
readonly type: "git";
|
|
1845
|
+
readonly url: string;
|
|
1846
|
+
readonly sourceType: "git";
|
|
1847
|
+
readonly extensionType: "mcp-server";
|
|
1848
|
+
readonly sourceName: "git";
|
|
1849
|
+
readonly packageFormat: "agentxm";
|
|
1850
|
+
readonly workspaceName: string & import("effect/Brand").Brand<"ExtensionName">;
|
|
1851
|
+
readonly packageOwner: string & import("effect/Brand").Brand<"Handle">;
|
|
1852
|
+
readonly packageName: string & import("effect/Brand").Brand<"ExtensionName">;
|
|
1853
|
+
readonly resolvedCommit: string;
|
|
1854
|
+
readonly resolvedTree: string;
|
|
1855
|
+
readonly contentIdentity: string & import("effect/Brand").Brand<"SourceHash">;
|
|
1856
|
+
readonly treeIntegrity: string & import("effect/Brand").Brand<"TreeIntegrity">;
|
|
1857
|
+
readonly path?: string | undefined;
|
|
1858
|
+
readonly ref?: string | undefined;
|
|
1859
|
+
} | {
|
|
1860
|
+
readonly type: "local";
|
|
1861
|
+
readonly sourceType: "local";
|
|
1862
|
+
readonly sourceName: "local";
|
|
1863
|
+
readonly extensionType: "mcp-server";
|
|
1864
|
+
readonly workspaceName: string & import("effect/Brand").Brand<"ExtensionName">;
|
|
1865
|
+
readonly packageFormat: "agentxm";
|
|
1866
|
+
readonly packageOwner: string & import("effect/Brand").Brand<"Handle">;
|
|
1867
|
+
readonly packageName: string & import("effect/Brand").Brand<"ExtensionName">;
|
|
1868
|
+
readonly path: string;
|
|
1869
|
+
readonly contentIdentity: string & import("effect/Brand").Brand<"SourceHash">;
|
|
1870
|
+
readonly treeIntegrity: string & import("effect/Brand").Brand<"TreeIntegrity">;
|
|
1871
|
+
} | {
|
|
1872
|
+
readonly type: "registry";
|
|
1873
|
+
readonly sourceType: "registry";
|
|
1874
|
+
readonly endpoint: URL;
|
|
1875
|
+
readonly extensionType: "mcp-server";
|
|
1876
|
+
readonly workspaceName: string & import("effect/Brand").Brand<"ExtensionName">;
|
|
1877
|
+
readonly packageFormat: "agentxm";
|
|
1878
|
+
readonly owner: string & import("effect/Brand").Brand<"Handle">;
|
|
1879
|
+
readonly name: string & import("effect/Brand").Brand<"ExtensionName">;
|
|
1880
|
+
readonly resolvedVersion: string & import("effect/Brand").Brand<"Version">;
|
|
1881
|
+
readonly integrity: string;
|
|
1882
|
+
readonly sourceName: string;
|
|
1883
|
+
readonly publisherBindingId: string;
|
|
1884
|
+
readonly treeIntegrity: string & import("effect/Brand").Brand<"TreeIntegrity">;
|
|
1885
|
+
}>, import("./read-model/errors.js").SettingsIoError | import("./read-model/errors.js").SettingsParseError | import("./read-model/errors.js").SettingsDecodeError | LockfileReadError | WorkspaceRootEscape, never>;
|
|
1886
|
+
setMcpServer: ({ name, resolutionKey, lockEntry, versionRange, env, enabled, agents, }: SetMcpServerArgs) => Effect.Effect<void, import("../settings/errors.ts").SettingsWriteError | import("./transaction.ts").WorkspaceSnapshotError | import("../lockfile/errors.js").LockfileWriteError | LockfileValidationError | SettingsReadError | LockfileReadError | WorkspaceRootEscape, never>;
|
|
1887
|
+
setMcpServerLock: ({ name: _name, resolutionKey, lockEntry }: SetMcpServerArgs) => Effect.Effect<void, import("../lockfile/errors.js").LockfileWriteError | LockfileValidationError | LockfileReadError | WorkspaceRootEscape, never>;
|
|
1655
1888
|
updateMcpServerEntry: (name: string, updater: (entry: McpServerEntry) => McpServerEntry) => Effect.Effect<void, import("../settings/errors.ts").SettingsWriteError | import("./transaction.ts").WorkspaceSnapshotError | SettingsEntryMissing | SettingsReadError | WorkspaceRootEscape, never>;
|
|
1656
1889
|
setMcpServerEntry: (name: string, entry: McpServerEntry) => Effect.Effect<void, import("../settings/errors.ts").SettingsWriteError | import("./transaction.ts").WorkspaceSnapshotError | SettingsReadError | WorkspaceRootEscape, never>;
|
|
1657
1890
|
removeMcpServer: (name: string) => Effect.Effect<void, import("../settings/errors.ts").SettingsWriteError | import("./transaction.ts").WorkspaceSnapshotError | import("../lockfile/errors.js").LockfileWriteError | LockfileValidationError | SettingsReadError | LockfileReadError | WorkspaceRootEscape, never>;
|
|
@@ -1660,6 +1893,6 @@ export declare const makeWorkspaceMutations: (options: WorkspaceLayerOptions, ma
|
|
|
1660
1893
|
removeMcpServerLock: (name: string) => Effect.Effect<void, import("../lockfile/errors.js").LockfileWriteError | LockfileValidationError | LockfileReadError | WorkspaceRootEscape, never>;
|
|
1661
1894
|
removePackSettings: (name: string) => Effect.Effect<void, import("../settings/errors.ts").SettingsWriteError | import("./transaction.ts").WorkspaceSnapshotError | SettingsReadError | WorkspaceRootEscape, never>;
|
|
1662
1895
|
removePackLock: (name: string) => Effect.Effect<void, import("../lockfile/errors.js").LockfileWriteError | LockfileValidationError | LockfileReadError | WorkspaceRootEscape, never>;
|
|
1663
|
-
isExtensionRequiredByInstalledPack: (target: ExtensionTarget) => Effect.Effect<boolean, DesiredPackGraphIncomplete |
|
|
1664
|
-
}, import("./errors.js").WorkspaceLayoutError | WorkspaceNotInitialized | WorkspaceSettingsReadFailure, FileSystem.FileSystem | Path.Path>;
|
|
1896
|
+
isExtensionRequiredByInstalledPack: (target: ExtensionTarget) => Effect.Effect<boolean, DesiredPackGraphIncomplete | import("./read-model/errors.js").SettingsIoError | import("./read-model/errors.js").SettingsParseError | import("./read-model/errors.js").SettingsDecodeError | import("./read-model/errors.js").LockfileIoError | import("./read-model/errors.js").LockfileParseError | import("./read-model/errors.js").LockfileDecodeError | LockfileVersionUnsupported | WorkspaceRootEscape, never>;
|
|
1897
|
+
}, import("./errors.js").WorkspaceLayoutError | WorkspaceNotInitialized | LockfileReadError | WorkspaceSettingsReadFailure, FileSystem.FileSystem | Path.Path>;
|
|
1665
1898
|
//# sourceMappingURL=service.d.ts.map
|
|
@@ -28,6 +28,7 @@ import { computePackPathsForLayout } from "./pack-paths.js";
|
|
|
28
28
|
import { sanitizeName } from "./extension-name.js";
|
|
29
29
|
import { ConfigurableAgentIdSchema, decodeExtensionNameSync, formatFqn, parseSourceQualifiedRegistrySourcePatternParts, } from "@agentxm/extension-model/unstable/extensions";
|
|
30
30
|
import { DesiredPackGraphIncomplete, InvalidAgentId, LockedSkillMissing, SettingsEntryMissing, WorkspaceNotInitialized, } from "./errors.js";
|
|
31
|
+
import { LockfileVersionUnsupported } from "./read-model/errors.js";
|
|
31
32
|
import { LockfileValidationError } from "../lockfile/errors.js";
|
|
32
33
|
import { createDefaultSettings, writeSettingsAtPath, } from "../settings/index.js";
|
|
33
34
|
import { DEFAULT_MINIMUM_RELEASE_AGE } from "@agentxm/registry-protocol/unstable/registry/release-age-policy";
|
|
@@ -71,15 +72,22 @@ const lockEntrySemanticallyEqual = (current, next) => current !== undefined && s
|
|
|
71
72
|
const skillLockEntrySemanticallyEqual = (current, next) => lockEntrySemanticallyEqual(current, next);
|
|
72
73
|
const preserveAcceptedResolutionOnNoop = (current, next) => (lockEntrySemanticallyEqual(current, next) && current !== undefined ? current : next);
|
|
73
74
|
const subagentLockEntrySemanticallyEqual = (current, next) => lockEntrySemanticallyEqual(current, next);
|
|
74
|
-
const requireInitializedWorkspace = (settingsPath, settings) => settings.pipe(Effect.flatMap(Option.match({
|
|
75
|
-
onNone: () => Effect.
|
|
75
|
+
const requireInitializedWorkspace = (settingsPath, settings, lockfile) => settings.pipe(Effect.flatMap(Option.match({
|
|
76
|
+
onNone: () => lockfile.pipe(Effect.matchEffect({
|
|
77
|
+
onFailure: (error) => error instanceof LockfileVersionUnsupported &&
|
|
78
|
+
error.observedVersion > error.supportedVersion
|
|
79
|
+
? Effect.fail(error)
|
|
80
|
+
: Effect.fail(new WorkspaceNotInitialized({ settingsPath })),
|
|
81
|
+
onSuccess: () => Effect.fail(new WorkspaceNotInitialized({ settingsPath })),
|
|
82
|
+
})),
|
|
76
83
|
onSome: () => Effect.void,
|
|
77
84
|
})));
|
|
78
85
|
/**
|
|
79
86
|
* Create the workspace mutations service from an existing workspace on disk.
|
|
80
87
|
*
|
|
81
|
-
* The workspace must already be initialized. Missing or invalid settings
|
|
82
|
-
* fast with a typed
|
|
88
|
+
* The workspace must already be initialized. Missing or invalid settings and
|
|
89
|
+
* invalid or unsupported lockfiles fail fast with a typed
|
|
90
|
+
* `WorkspaceMutationsError`. The two operations-side
|
|
83
91
|
* capabilities — the transaction runner and transition acquirer — are
|
|
84
92
|
* injected through `makeCapabilities`; the composition seam in
|
|
85
93
|
* `./operations/load-workspace.ts` supplies the live implementation.
|
|
@@ -112,7 +120,8 @@ export const makeWorkspaceMutations = (options, makeCapabilities) => Effect.gen(
|
|
|
112
120
|
const readSettingsCell = (dir, sharedScope) => makeWorkspaceReadModel(scopeForDir(dir, sharedScope)).pipe(Effect.flatMap((readModel) => readModel.state.settings), Effect.provide(contextEnv));
|
|
113
121
|
const readLockfileCell = (dir, sharedScope) => makeWorkspaceReadModel(scopeForDir(dir, sharedScope)).pipe(Effect.flatMap((readModel) => readModel.state.lockfile), Effect.map(Option.getOrElse(createEmptyLockfile)), Effect.provide(contextEnv));
|
|
114
122
|
if (options.allowUninitialized !== true) {
|
|
115
|
-
yield* requireInitializedWorkspace(settingsPath, readSettingsCell(workspaceDir));
|
|
123
|
+
yield* requireInitializedWorkspace(settingsPath, readSettingsCell(workspaceDir), readLockfileCell(workspaceDir));
|
|
124
|
+
yield* readLockfileCell(workspaceDir);
|
|
116
125
|
}
|
|
117
126
|
const projectSettings = yield* readSettingsCell(localRuntimeDir, "project").pipe(Effect.map(Option.getOrElse(() => createDefaultSettings())));
|
|
118
127
|
const userSettings = yield* readSettingsCell(userRuntimeDir, "user").pipe(Effect.map(Option.getOrElse(() => createDefaultSettings())));
|
|
@@ -161,15 +170,23 @@ export const makeWorkspaceMutations = (options, makeCapabilities) => Effect.gen(
|
|
|
161
170
|
}
|
|
162
171
|
// An unreadable or corrupt lockfile is actionable workspace state,
|
|
163
172
|
// not a violated invariant.
|
|
164
|
-
return yield* readLockfileSafe(workspaceDir).pipe(Effect.as("ok"), Effect.catchTag([
|
|
173
|
+
return yield* readLockfileSafe(workspaceDir).pipe(Effect.as("ok"), Effect.catchTag([
|
|
174
|
+
"LockfileIoError",
|
|
175
|
+
"LockfileParseError",
|
|
176
|
+
"LockfileDecodeError",
|
|
177
|
+
"LockfileVersionUnsupported",
|
|
178
|
+
], () => Effect.succeed("invalid")));
|
|
165
179
|
}).pipe(Effect.withSpan("WorkspaceMutations.getLockfileState"));
|
|
166
180
|
const readScopedContext = (f) => makeWorkspaceReadModel(scopeForDir(workspaceDir)).pipe(Effect.flatMap(f), Effect.provide(contextEnv));
|
|
167
181
|
const readDesiredStateGraph = (graphOptions) => Effect.gen(function* () {
|
|
168
182
|
const settings = yield* readSettingsSafe(workspaceDir);
|
|
183
|
+
const configuredSources = yield* getConfiguredSources();
|
|
184
|
+
const registryAuthorities = Object.fromEntries(configuredSources.flatMap((source) => source.type === "registry" ? [[source.name, source.location]] : []));
|
|
169
185
|
const graph = yield* buildDesiredStateGraph({
|
|
170
186
|
baseDir,
|
|
171
187
|
settings,
|
|
172
188
|
layout,
|
|
189
|
+
registryAuthorities,
|
|
173
190
|
...(graphOptions?.prospectivePacks === undefined
|
|
174
191
|
? {}
|
|
175
192
|
: { prospectivePacks: graphOptions.prospectivePacks }),
|
|
@@ -1083,8 +1100,16 @@ export const makeWorkspaceMutations = (options, makeCapabilities) => Effect.gen(
|
|
|
1083
1100
|
// MCP Server methods
|
|
1084
1101
|
// -----------------------------------------------------------------------
|
|
1085
1102
|
getLockedMcpServers: () => readLockfileSafe(workspaceDir).pipe(Effect.map((lf) => lf.mcpServers ?? {})),
|
|
1086
|
-
getLockedMcpServer: (
|
|
1087
|
-
|
|
1103
|
+
getLockedMcpServer: (resolutionKey) => readLockfileSafe(workspaceDir).pipe(Effect.map((lf) => Option.fromUndefinedOr((lf.mcpServers ?? {})[resolutionKey]))),
|
|
1104
|
+
getLockedMcpServerForConnection: (localName) => Effect.gen(function* () {
|
|
1105
|
+
const graph = yield* readDesiredStateGraph();
|
|
1106
|
+
const node = graph.nodes.find((candidate) => candidate.type === "mcp-server" && candidate.name === localName);
|
|
1107
|
+
if (node === undefined || node.authority === "inline")
|
|
1108
|
+
return Option.none();
|
|
1109
|
+
const lockfile = yield* readLockfileSafe(workspaceDir);
|
|
1110
|
+
return Option.fromUndefinedOr((lockfile.mcpServers ?? {})[node.identity]);
|
|
1111
|
+
}),
|
|
1112
|
+
setMcpServer: ({ name, resolutionKey, lockEntry, versionRange, env, enabled, agents, }) => withMutex(Effect.gen(function* () {
|
|
1088
1113
|
// Update settings (uses "mcpServers" key)
|
|
1089
1114
|
const currentSettings = yield* readSettingsSafe(workspaceDir);
|
|
1090
1115
|
const currentMcpServers = currentSettings.mcpServers ?? {};
|
|
@@ -1098,7 +1123,7 @@ export const makeWorkspaceMutations = (options, makeCapabilities) => Effect.gen(
|
|
|
1098
1123
|
const fqn = formatFqn({
|
|
1099
1124
|
owner: lockEntry.owner,
|
|
1100
1125
|
type: "mcp-server",
|
|
1101
|
-
name:
|
|
1126
|
+
name: lockEntry.name,
|
|
1102
1127
|
});
|
|
1103
1128
|
const locator = Option.isSome(versionRange)
|
|
1104
1129
|
? `${fqn}@${versionRange.value}`
|
|
@@ -1127,12 +1152,12 @@ export const makeWorkspaceMutations = (options, makeCapabilities) => Effect.gen(
|
|
|
1127
1152
|
...currentLockfile,
|
|
1128
1153
|
mcpServers: {
|
|
1129
1154
|
...currentLockedMcpServers,
|
|
1130
|
-
[
|
|
1155
|
+
[resolutionKey]: preserveAcceptedResolutionOnNoop(currentLockedMcpServers[resolutionKey], lockEntry),
|
|
1131
1156
|
},
|
|
1132
1157
|
};
|
|
1133
1158
|
yield* commitWorkspaceState(currentLockfile, updatedLockfile);
|
|
1134
1159
|
})).pipe(Effect.withSpan("WorkspaceMutations.setMcpServer")),
|
|
1135
|
-
setMcpServerLock: ({ name, lockEntry }) => withMutex(Effect.gen(function* () {
|
|
1160
|
+
setMcpServerLock: ({ name: _name, resolutionKey, lockEntry }) => withMutex(Effect.gen(function* () {
|
|
1136
1161
|
// Update lockfile only (skip settings) — used for pack dependencies
|
|
1137
1162
|
const currentLockfile = yield* readLockfileSafe(workspaceDir);
|
|
1138
1163
|
const currentLockedMcpServers = currentLockfile.mcpServers ?? {};
|
|
@@ -1140,7 +1165,7 @@ export const makeWorkspaceMutations = (options, makeCapabilities) => Effect.gen(
|
|
|
1140
1165
|
...currentLockfile,
|
|
1141
1166
|
mcpServers: {
|
|
1142
1167
|
...currentLockedMcpServers,
|
|
1143
|
-
[
|
|
1168
|
+
[resolutionKey]: preserveAcceptedResolutionOnNoop(currentLockedMcpServers[resolutionKey], lockEntry),
|
|
1144
1169
|
},
|
|
1145
1170
|
};
|
|
1146
1171
|
yield* commitWorkspaceState(currentLockfile, updatedLockfile);
|
|
@@ -1166,6 +1191,11 @@ export const makeWorkspaceMutations = (options, makeCapabilities) => Effect.gen(
|
|
|
1166
1191
|
yield* writeScopedSettings(updatedSettings).pipe(Effect.provide(fsLayer));
|
|
1167
1192
|
})),
|
|
1168
1193
|
removeMcpServer: (name) => withMutex(Effect.gen(function* () {
|
|
1194
|
+
const graph = yield* readDesiredStateGraph();
|
|
1195
|
+
const desiredNode = graph.nodes.find((node) => node.type === "mcp-server" && node.name === name);
|
|
1196
|
+
const closure = desiredNode === undefined || desiredNode.authority === "inline"
|
|
1197
|
+
? undefined
|
|
1198
|
+
: graph.mcpSourceClosures.find((candidate) => candidate.identity === desiredNode.identity);
|
|
1169
1199
|
// Update settings (uses "mcpServers" key)
|
|
1170
1200
|
const currentSettings = yield* readSettingsSafe(workspaceDir);
|
|
1171
1201
|
const currentMcpServers = currentSettings.mcpServers ?? {};
|
|
@@ -1182,8 +1212,14 @@ export const makeWorkspaceMutations = (options, makeCapabilities) => Effect.gen(
|
|
|
1182
1212
|
// Update lockfile (uses "mcpServers" key)
|
|
1183
1213
|
const currentLockfile = yield* readLockfileSafe(workspaceDir);
|
|
1184
1214
|
const currentLockedMcpServers = currentLockfile.mcpServers ?? {};
|
|
1185
|
-
|
|
1186
|
-
|
|
1215
|
+
const resolutionKey = desiredNode?.identity;
|
|
1216
|
+
const keepSharedResolution = closure !== undefined &&
|
|
1217
|
+
(closure.localNames.length > 1 ||
|
|
1218
|
+
closure.origins.some((origin) => origin.type === "pack"));
|
|
1219
|
+
if (resolutionKey !== undefined &&
|
|
1220
|
+
!keepSharedResolution &&
|
|
1221
|
+
resolutionKey in currentLockedMcpServers) {
|
|
1222
|
+
const { [resolutionKey]: __, ...remainingLockedMcpServers } = currentLockedMcpServers;
|
|
1187
1223
|
void __;
|
|
1188
1224
|
const updatedLockfile = {
|
|
1189
1225
|
...currentLockfile,
|
|
@@ -188,7 +188,7 @@ export const makeBaseWorkspaceMock = (axmDir = "/tmp/axm", overrides) => {
|
|
|
188
188
|
],
|
|
189
189
|
};
|
|
190
190
|
}));
|
|
191
|
-
return { complete: true, nodes, problems: [] };
|
|
191
|
+
return { complete: true, nodes, mcpSourceClosures: [], problems: [] };
|
|
192
192
|
});
|
|
193
193
|
const runTransaction = (args) => Effect.gen(function* () {
|
|
194
194
|
const value = yield* args.transition;
|
|
@@ -304,6 +304,7 @@ export const makeBaseWorkspaceMock = (axmDir = "/tmp/axm", overrides) => {
|
|
|
304
304
|
removeSubagentLock: () => Effect.void,
|
|
305
305
|
getLockedMcpServers: lockedMcpServers,
|
|
306
306
|
getLockedMcpServer: entryFrom(lockedMcpServers),
|
|
307
|
+
getLockedMcpServerForConnection: entryFrom(lockedMcpServers),
|
|
307
308
|
setMcpServer: () => Effect.void,
|
|
308
309
|
setMcpServerLock: () => Effect.void,
|
|
309
310
|
updateMcpServerEntry: () => Effect.void,
|
|
@@ -337,7 +338,7 @@ export const writeWorkspaceFiles = (runtimeDir, opts = {}) => {
|
|
|
337
338
|
...(opts.sources && { sources: opts.sources }),
|
|
338
339
|
};
|
|
339
340
|
const lockfile = {
|
|
340
|
-
lockfileVersion:
|
|
341
|
+
lockfileVersion: 7,
|
|
341
342
|
skills: opts.lockfileSkills ?? {},
|
|
342
343
|
...(hasEntries(opts.lockfileMcpServers) && { mcps: opts.lockfileMcpServers }),
|
|
343
344
|
...(hasEntries(opts.lockfileSubagents) && { subagents: opts.lockfileSubagents }),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentxm/workspace-state",
|
|
3
|
-
"version": "0.28.
|
|
3
|
+
"version": "0.28.5",
|
|
4
4
|
"description": "AXM workspace state kernel: settings, lockfile, read model, and desired-state vocabulary for the axm CLI. Unstable and unsupported — use the axm.sh CLI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "FSL-1.1-MIT",
|
|
@@ -18,10 +18,12 @@
|
|
|
18
18
|
"exports": {
|
|
19
19
|
".": {
|
|
20
20
|
"types": "./dist/src/index.d.ts",
|
|
21
|
+
"axm-source": "./src/index.ts",
|
|
21
22
|
"default": "./dist/src/index.js"
|
|
22
23
|
},
|
|
23
24
|
"./testing": {
|
|
24
25
|
"types": "./dist/src/testing.d.ts",
|
|
26
|
+
"axm-source": "./src/testing.ts",
|
|
25
27
|
"default": "./dist/src/testing.js"
|
|
26
28
|
}
|
|
27
29
|
},
|
|
@@ -43,8 +45,8 @@
|
|
|
43
45
|
"jsonc-parser": "^3.3.1",
|
|
44
46
|
"semver": "^7.8.5",
|
|
45
47
|
"yaml": "^2.9.0",
|
|
46
|
-
"@agentxm/
|
|
47
|
-
"@agentxm/
|
|
48
|
+
"@agentxm/extension-model": "^0.28.5",
|
|
49
|
+
"@agentxm/registry-protocol": "^0.28.5"
|
|
48
50
|
},
|
|
49
51
|
"devDependencies": {
|
|
50
52
|
"@effect/platform-node": "4.0.0-rc.112",
|