@agentxm/workspace-state 0.28.12 → 0.28.13

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.
Files changed (85) hide show
  1. package/dist/src/index.d.ts +22 -13
  2. package/dist/src/index.js +25 -16
  3. package/dist/src/live.d.ts +46 -0
  4. package/dist/src/live.js +60 -0
  5. package/dist/src/lockfile/lockfile.js +1 -2
  6. package/dist/src/settings/index.d.ts +1 -1
  7. package/dist/src/settings/index.js +1 -1
  8. package/dist/src/settings/schema.d.ts +12 -0
  9. package/dist/src/settings/schema.js +13 -1
  10. package/dist/src/settings/settings.d.ts +1 -1
  11. package/dist/src/settings/settings.js +1 -3
  12. package/dist/src/testing.d.ts +24 -0
  13. package/dist/src/testing.js +35 -0
  14. package/dist/src/utils/path-safety.d.ts +0 -5
  15. package/dist/src/utils/path-safety.js +1 -10
  16. package/dist/src/workspace/accepted-canonical-ref.d.ts +1 -1
  17. package/dist/src/workspace/accepted-canonical-ref.js +1 -1
  18. package/dist/src/workspace/accepted-resolution-writer.d.ts +42 -0
  19. package/dist/src/workspace/accepted-resolution-writer.js +67 -0
  20. package/dist/src/workspace/canonical-observation.js +1 -1
  21. package/dist/src/workspace/configured-entry.d.ts +11 -0
  22. package/dist/src/workspace/configured-entry.js +8 -0
  23. package/dist/src/workspace/create-symlink.d.ts +1 -1
  24. package/dist/src/workspace/create-symlink.js +1 -2
  25. package/dist/src/workspace/desired-identity.d.ts +19 -0
  26. package/dist/src/workspace/desired-identity.js +26 -0
  27. package/dist/src/workspace/desired-state-reader.d.ts +32 -0
  28. package/dist/src/workspace/desired-state-reader.js +56 -0
  29. package/dist/src/workspace/desired-state-writer.d.ts +46 -0
  30. package/dist/src/workspace/desired-state-writer.js +214 -0
  31. package/dist/src/workspace/entry-accessors.d.ts +50 -0
  32. package/dist/src/workspace/entry-accessors.js +41 -0
  33. package/dist/src/workspace/extension-paths-service.d.ts +33 -0
  34. package/dist/src/workspace/extension-paths-service.js +133 -0
  35. package/dist/src/workspace/location.d.ts +49 -0
  36. package/dist/src/workspace/location.js +85 -0
  37. package/dist/src/workspace/lockfile-reader.d.ts +41 -0
  38. package/dist/src/workspace/lockfile-reader.js +54 -0
  39. package/dist/src/workspace/materialized-file-target.d.ts +2 -2
  40. package/dist/src/workspace/materialized-file-target.js +2 -2
  41. package/dist/src/workspace/other-scope-reader.d.ts +34 -0
  42. package/dist/src/workspace/other-scope-reader.js +35 -0
  43. package/dist/src/workspace/paths.d.ts +2 -2
  44. package/dist/src/workspace/read-model/__fixtures__/test-layer.d.ts +1 -1
  45. package/dist/src/workspace/read-model/__fixtures__/test-layer.js +1 -1
  46. package/dist/src/workspace/read-model/discovery/skills.d.ts +1 -1
  47. package/dist/src/workspace/read-model/discovery/skills.js +1 -1
  48. package/dist/src/workspace/read-model/scanners/canonical-extensions.js +2 -2
  49. package/dist/src/workspace/read-model/scanners/mcp-config.js +1 -1
  50. package/dist/src/workspace/read-model/service.js +1 -1
  51. package/dist/src/workspace/read-model-record-readers.js +1 -1
  52. package/dist/src/workspace/remove-if-exists.d.ts +1 -1
  53. package/dist/src/workspace/remove-if-exists.js +1 -2
  54. package/dist/src/workspace/service-interface.d.ts +8 -60
  55. package/dist/src/workspace/service.d.ts +26 -1886
  56. package/dist/src/workspace/service.js +144 -1285
  57. package/dist/src/workspace/settings-reader.d.ts +59 -0
  58. package/dist/src/workspace/settings-reader.js +109 -0
  59. package/dist/src/workspace/settings-writer.d.ts +53 -0
  60. package/dist/src/workspace/settings-writer.js +90 -0
  61. package/dist/src/workspace/setup-scope-support.js +1 -1
  62. package/dist/src/workspace/shared.d.ts +24 -0
  63. package/dist/src/workspace/shared.js +20 -0
  64. package/dist/src/workspace/state-cells.d.ts +35 -0
  65. package/dist/src/workspace/state-cells.js +42 -0
  66. package/dist/src/workspace/subagent-paths.d.ts +49 -0
  67. package/dist/src/workspace/subagent-paths.js +26 -0
  68. package/dist/src/workspace/test-stubs.js +0 -11
  69. package/dist/src/workspace/workspace-records.d.ts +41 -0
  70. package/dist/src/workspace/workspace-records.js +43 -0
  71. package/package.json +14 -5
  72. package/dist/src/utils/atomic-write.d.ts +0 -67
  73. package/dist/src/utils/atomic-write.js +0 -71
  74. package/dist/src/workspace/configured-entry-resolution/types.d.ts +0 -32
  75. package/dist/src/workspace/configured-entry-resolution/types.js +0 -2
  76. package/dist/src/workspace/footprint-recorder.d.ts +0 -30
  77. package/dist/src/workspace/footprint-recorder.js +0 -32
  78. package/dist/src/workspace/mcp-entry-semantics.d.ts +0 -28
  79. package/dist/src/workspace/mcp-entry-semantics.js +0 -58
  80. package/dist/src/workspace/read-model/agent-presence.d.ts +0 -32
  81. package/dist/src/workspace/read-model/agent-presence.js +0 -21
  82. package/dist/src/workspace/scope-refusal.d.ts +0 -26
  83. package/dist/src/workspace/scope-refusal.js +0 -29
  84. package/dist/src/workspace/transaction.d.ts +0 -219
  85. package/dist/src/workspace/transaction.js +0 -177
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Extension paths: where the selected scope keeps a skill's or Pack's
3
+ * canonical content. Skill directories for Registry sources follow the
4
+ * immutable Registry name, resolved from the accepted lock entry, then the
5
+ * configured source, then the name given; every other source uses the shared
6
+ * acquired-extensions directory.
7
+ *
8
+ * @experimental This API is unstable and may change without notice.
9
+ */
10
+ import * as ServiceMap from "effect/Context";
11
+ import * as Effect from "effect/Effect";
12
+ import type * as FileSystem from "effect/FileSystem";
13
+ import * as Layer from "effect/Layer";
14
+ import * as Path from "effect/Path";
15
+ import type { Handle } from "@agentxm/extension-model/unstable/extensions/handle";
16
+ import { LockedSkillMissing } from "./errors.js";
17
+ import { LockfileReader, type LockfileReaderService } from "./lockfile-reader.js";
18
+ import { WorkspaceLocation, type WorkspaceLocationService } from "./location.js";
19
+ import type { PackDirPath, SkillDirPaths, SkillPathSource, WorkspaceStateReadFailure } from "./service-interface.js";
20
+ import { SettingsReader, type SettingsReaderService } from "./settings-reader.js";
21
+ export interface ExtensionPathsService {
22
+ /** Skill directory paths. Without a source, the accepted lock entry decides the layout. */
23
+ readonly skillDir: (name: string, source?: SkillPathSource) => Effect.Effect<SkillDirPaths, WorkspaceStateReadFailure | LockedSkillMissing, FileSystem.FileSystem | Path.Path>;
24
+ /** The Pack directory path. Packs are always registry-sourced. */
25
+ readonly packDir: (name: string, owner: Handle, sourceName: string) => Effect.Effect<PackDirPath, never, Path.Path>;
26
+ }
27
+ declare const ExtensionPaths_base: ServiceMap.ServiceClass<ExtensionPaths, "@agentxm/workspace-state/ExtensionPaths", ExtensionPathsService>;
28
+ export declare class ExtensionPaths extends ExtensionPaths_base {
29
+ }
30
+ export declare const makeExtensionPaths: (location: WorkspaceLocationService, settings: SettingsReaderService, lockfile: LockfileReaderService) => ExtensionPathsService;
31
+ export declare const ExtensionPathsLive: Layer.Layer<ExtensionPaths, never, WorkspaceLocation | SettingsReader | LockfileReader>;
32
+ export {};
33
+ //# sourceMappingURL=extension-paths-service.d.ts.map
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Extension paths: where the selected scope keeps a skill's or Pack's
3
+ * canonical content. Skill directories for Registry sources follow the
4
+ * immutable Registry name, resolved from the accepted lock entry, then the
5
+ * configured source, then the name given; every other source uses the shared
6
+ * acquired-extensions directory.
7
+ *
8
+ * @experimental This API is unstable and may change without notice.
9
+ */
10
+ import * as ServiceMap from "effect/Context";
11
+ import * as Effect from "effect/Effect";
12
+ import * as Layer from "effect/Layer";
13
+ import * as Option from "effect/Option";
14
+ import * as Path from "effect/Path";
15
+ import * as Ref from "effect/Ref";
16
+ import { parseSourceQualifiedRegistrySourcePatternParts } from "@agentxm/extension-model/unstable/extensions";
17
+ import { LockedSkillMissing } from "./errors.js";
18
+ import { sanitizeName } from "./extension-name.js";
19
+ import { LockfileReader } from "./lockfile-reader.js";
20
+ import { WorkspaceLocation } from "./location.js";
21
+ import { computePackPathsForLayout } from "./pack-paths.js";
22
+ import { SettingsReader } from "./settings-reader.js";
23
+ import { computeSkillPathsForLayout } from "./skill-paths.js";
24
+ export class ExtensionPaths extends ServiceMap.Service()("@agentxm/workspace-state/ExtensionPaths") {
25
+ }
26
+ export const makeExtensionPaths = (location, settings, lockfile) => {
27
+ /**
28
+ * Resolve the immutable registry name for a skill's directory: the lockfile
29
+ * first, then the configured source string, then the given name (correct
30
+ * for fresh installs).
31
+ */
32
+ const resolveRegistryDirName = (name) => Effect.gen(function* () {
33
+ const lockEntry = yield* lockfile.entry("skill", name);
34
+ if (Option.isSome(lockEntry) && lockEntry.value.type === "registry") {
35
+ return lockEntry.value.name;
36
+ }
37
+ const entry = (yield* settings.entries("skill"))[name];
38
+ if (entry !== undefined) {
39
+ const parsed = parseSourceQualifiedRegistrySourcePatternParts(entry.source);
40
+ if (parsed?.name !== undefined)
41
+ return parsed.name;
42
+ }
43
+ return name;
44
+ });
45
+ return {
46
+ skillDir: (name, source) => Effect.gen(function* () {
47
+ const path = yield* Path.Path;
48
+ const layout = yield* Ref.get(location.layout);
49
+ if (source !== undefined) {
50
+ const dirName = source.refType === "registry" ? yield* resolveRegistryDirName(name) : name;
51
+ return computeSkillPathsForLayout(path.join, layout, source, sanitizeName(dirName));
52
+ }
53
+ const lockEntry = yield* lockfile.entry("skill", name);
54
+ if (Option.isNone(lockEntry)) {
55
+ return yield* new LockedSkillMissing({ name });
56
+ }
57
+ const entry = lockEntry.value;
58
+ const entrySource = (() => {
59
+ switch (entry.type) {
60
+ case "registry":
61
+ return {
62
+ refType: "registry",
63
+ owner: entry.owner,
64
+ source: {
65
+ type: "registry",
66
+ name: entry.sourceName,
67
+ location: entry.endpoint,
68
+ owner: Option.some(entry.owner),
69
+ },
70
+ };
71
+ case "local":
72
+ return {
73
+ refType: "local",
74
+ source: { type: "local", path: entry.path },
75
+ sourcePath: entry.path,
76
+ };
77
+ case "github":
78
+ case "gitlab":
79
+ case "bitbucket":
80
+ return {
81
+ refType: "git-hosted",
82
+ source: {
83
+ type: entry.type,
84
+ name: entry.sourceName,
85
+ url: entry.endpoint,
86
+ owner: entry.owner,
87
+ repo: entry.repo,
88
+ ref: Option.fromUndefinedOr(entry.ref),
89
+ subPath: Option.fromUndefinedOr(entry.path),
90
+ },
91
+ ...(entry.path === undefined ? {} : { sourcePath: entry.path }),
92
+ };
93
+ case "azurerepos":
94
+ return {
95
+ refType: "git-hosted",
96
+ source: {
97
+ type: "azurerepos",
98
+ name: entry.sourceName,
99
+ url: entry.endpoint,
100
+ organization: entry.organization,
101
+ project: entry.project,
102
+ repo: entry.repo,
103
+ ref: Option.fromUndefinedOr(entry.ref),
104
+ subPath: Option.fromUndefinedOr(entry.path),
105
+ },
106
+ ...(entry.path === undefined ? {} : { sourcePath: entry.path }),
107
+ };
108
+ case "git":
109
+ return {
110
+ refType: "git-hosted",
111
+ source: {
112
+ type: "git",
113
+ url: new URL(entry.url),
114
+ ref: Option.fromUndefinedOr(entry.ref),
115
+ },
116
+ ...(entry.path === undefined ? {} : { sourcePath: entry.path }),
117
+ };
118
+ }
119
+ })();
120
+ const dirName = entry.type === "registry" ? entry.name : entry.packageName;
121
+ return computeSkillPathsForLayout(path.join, layout, entrySource, sanitizeName(dirName));
122
+ }),
123
+ packDir: (name, owner, sourceName) => Effect.gen(function* () {
124
+ const path = yield* Path.Path;
125
+ const layout = yield* Ref.get(location.layout);
126
+ return computePackPathsForLayout(path.join, layout, sourceName, owner, name);
127
+ }),
128
+ };
129
+ };
130
+ export const ExtensionPathsLive = Layer.effect(ExtensionPaths, Effect.gen(function* () {
131
+ return makeExtensionPaths(yield* WorkspaceLocation, yield* SettingsReader, yield* LockfileReader);
132
+ }));
133
+ //# sourceMappingURL=extension-paths-service.js.map
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Workspace location: the resolved identity of the selected workspace scope.
3
+ *
4
+ * One value per workspace lifetime naming the scope, its runtime state
5
+ * directory, the two shared authoritative files, the project and user
6
+ * runtime directories both settings sources live in, and the resolved
7
+ * layout. The layout is a `Ref` because recording an owner replaces it for
8
+ * the resolution that follows in the same run; only `SettingsWriter.setOwner`
9
+ * updates it. Every narrow state service reads its paths from here.
10
+ *
11
+ * @experimental This API is unstable and may change without notice.
12
+ */
13
+ import * as ServiceMap from "effect/Context";
14
+ import * as Effect from "effect/Effect";
15
+ import type * as FileSystem from "effect/FileSystem";
16
+ import * as Path from "effect/Path";
17
+ import * as Ref from "effect/Ref";
18
+ import type { WorkspaceScope } from "@agentxm/extension-model/unstable/workspace-scope";
19
+ import { type SourceHostConfig } from "../settings/index.js";
20
+ import { type WorkspaceLayout } from "./layout.js";
21
+ import type { WorkspaceMutationsError, WorkspaceMutationsOptions } from "./service-interface.js";
22
+ import { type StateCellPaths } from "./state-cells.js";
23
+ export interface WorkspaceLocationService extends StateCellPaths {
24
+ /** Whether this is the user workspace or a project workspace. */
25
+ readonly scope: WorkspaceScope;
26
+ /** User home or project root that anchors scope resolution. */
27
+ readonly baseDir: string;
28
+ /** The selected scope's runtime `.axm` directory. */
29
+ readonly runtimeDir: string;
30
+ readonly settingsPath: string;
31
+ readonly lockPath: string;
32
+ /** The resolved layout; replaced only when an owner is recorded. */
33
+ readonly layout: Ref.Ref<WorkspaceLayout>;
34
+ /** Built-in source hosts merged behind project and user settings. */
35
+ readonly builtInSources: ReadonlyArray<SourceHostConfig>;
36
+ }
37
+ declare const WorkspaceLocation_base: ServiceMap.ServiceClass<WorkspaceLocation, "@agentxm/workspace-state/WorkspaceLocation", WorkspaceLocationService>;
38
+ export declare class WorkspaceLocation extends WorkspaceLocation_base {
39
+ }
40
+ /**
41
+ * Resolve the workspace location from an existing workspace on disk.
42
+ *
43
+ * The workspace must already be initialized unless `allowUninitialized` is
44
+ * set. Missing or invalid settings and invalid or unsupported lockfiles fail
45
+ * fast with a typed `WorkspaceMutationsError`.
46
+ */
47
+ export declare const makeWorkspaceLocation: (options: WorkspaceMutationsOptions) => Effect.Effect<WorkspaceLocationService, WorkspaceMutationsError, FileSystem.FileSystem | Path.Path>;
48
+ export {};
49
+ //# sourceMappingURL=location.d.ts.map
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Workspace location: the resolved identity of the selected workspace scope.
3
+ *
4
+ * One value per workspace lifetime naming the scope, its runtime state
5
+ * directory, the two shared authoritative files, the project and user
6
+ * runtime directories both settings sources live in, and the resolved
7
+ * layout. The layout is a `Ref` because recording an owner replaces it for
8
+ * the resolution that follows in the same run; only `SettingsWriter.setOwner`
9
+ * updates it. Every narrow state service reads its paths from here.
10
+ *
11
+ * @experimental This API is unstable and may change without notice.
12
+ */
13
+ import * as ServiceMap from "effect/Context";
14
+ import * as Effect from "effect/Effect";
15
+ import * as Option from "effect/Option";
16
+ import * as Path from "effect/Path";
17
+ import * as Ref from "effect/Ref";
18
+ import { createDefaultSettings } from "../settings/index.js";
19
+ import { WorkspaceNotInitialized } from "./errors.js";
20
+ import { resolveProjectWorkspaceLayout, resolveProjectWorkspaceStatePaths, resolveUserWorkspaceLayout, } from "./layout.js";
21
+ import { getProjectRuntimeDir, resolveUserHome } from "./paths.js";
22
+ import { LockfileVersionUnsupported } from "./read-model/errors.js";
23
+ import { readLockfileCell, readSettingsCell } from "./state-cells.js";
24
+ export class WorkspaceLocation extends ServiceMap.Service()("@agentxm/workspace-state/WorkspaceLocation") {
25
+ }
26
+ const requireInitializedWorkspace = (settingsPath, settings, lockfile) => settings.pipe(Effect.flatMap(Option.match({
27
+ onNone: () => lockfile.pipe(Effect.matchEffect({
28
+ onFailure: (error) => error instanceof LockfileVersionUnsupported &&
29
+ error.observedVersion > error.supportedVersion
30
+ ? Effect.fail(error)
31
+ : Effect.fail(new WorkspaceNotInitialized({ settingsPath })),
32
+ onSuccess: () => Effect.fail(new WorkspaceNotInitialized({ settingsPath })),
33
+ })),
34
+ onSome: () => Effect.void,
35
+ })));
36
+ const defaultBuiltInSources = [
37
+ { name: "github", type: "github", url: new URL("https://github.com") },
38
+ { name: "gitlab", type: "gitlab", url: new URL("https://gitlab.com") },
39
+ { name: "bitbucket", type: "bitbucket", url: new URL("https://bitbucket.org") },
40
+ ];
41
+ /**
42
+ * Resolve the workspace location from an existing workspace on disk.
43
+ *
44
+ * The workspace must already be initialized unless `allowUninitialized` is
45
+ * set. Missing or invalid settings and invalid or unsupported lockfiles fail
46
+ * fast with a typed `WorkspaceMutationsError`.
47
+ */
48
+ export const makeWorkspaceLocation = (options) => Effect.gen(function* () {
49
+ const path = yield* Path.Path;
50
+ const userHome = yield* resolveUserHome();
51
+ const initialUserLayout = yield* resolveUserWorkspaceLayout(userHome);
52
+ const userRuntimeDir = initialUserLayout.runtimeDir;
53
+ const projectRuntimeDir = yield* getProjectRuntimeDir(options.projectRoot);
54
+ const runtimeDir = options.scope === "user" ? userRuntimeDir : projectRuntimeDir;
55
+ const initialProjectState = resolveProjectWorkspaceStatePaths(path, options.projectRoot);
56
+ const settingsPath = options.scope === "user" ? initialUserLayout.settingsPath : initialProjectState.settingsPath;
57
+ const lockPath = options.scope === "user" ? initialUserLayout.lockPath : initialProjectState.lockPath;
58
+ const baseDir = options.scope === "user" ? userHome : options.projectRoot;
59
+ const cells = {
60
+ scope: options.scope,
61
+ projectRoot: options.projectRoot,
62
+ userHome,
63
+ projectRuntimeDir,
64
+ userRuntimeDir,
65
+ };
66
+ if (options.allowUninitialized !== true) {
67
+ yield* requireInitializedWorkspace(settingsPath, readSettingsCell(cells, runtimeDir), readLockfileCell(cells, runtimeDir));
68
+ yield* readLockfileCell(cells, runtimeDir);
69
+ }
70
+ const projectSettings = yield* readSettingsCell(cells, projectRuntimeDir, "project").pipe(Effect.map(Option.getOrElse(() => createDefaultSettings())));
71
+ const userSettings = yield* readSettingsCell(cells, userRuntimeDir, "user").pipe(Effect.map(Option.getOrElse(() => createDefaultSettings())));
72
+ const projectLayout = yield* resolveProjectWorkspaceLayout(options.projectRoot, projectSettings);
73
+ const userLayout = yield* resolveUserWorkspaceLayout(userHome, userSettings);
74
+ const layout = yield* Ref.make(options.scope === "project" ? projectLayout : userLayout);
75
+ return {
76
+ ...cells,
77
+ baseDir,
78
+ runtimeDir,
79
+ settingsPath,
80
+ lockPath,
81
+ layout,
82
+ builtInSources: options.builtInSources ?? defaultBuiltInSources,
83
+ };
84
+ });
85
+ //# sourceMappingURL=location.js.map
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Lockfile reader: the selected scope's accepted resolutions — the lockfile
3
+ * health probe, the per-type entry maps, one entry by name, and the shared
4
+ * MCP resolution a local connection name accepts.
5
+ *
6
+ * @experimental This API is unstable and may change without notice.
7
+ */
8
+ import * as ServiceMap from "effect/Context";
9
+ import * as Effect from "effect/Effect";
10
+ import * as FileSystem from "effect/FileSystem";
11
+ import * as Layer from "effect/Layer";
12
+ import * as Option from "effect/Option";
13
+ import type * as Path from "effect/Path";
14
+ import type { InstallableExtensionType } from "@agentxm/extension-model/unstable/extensions/installable-types";
15
+ import { LockfileValidationError } from "../lockfile/errors.js";
16
+ import type { Lockfile, McpServerLockEntry } from "../lockfile/schema.js";
17
+ import { DesiredStateReader, type DesiredStateReaderService } from "./desired-state-reader.js";
18
+ import { type LockEntriesOf, type LockEntryByType } from "./entry-accessors.js";
19
+ import { WorkspaceLocation, type WorkspaceLocationService } from "./location.js";
20
+ import type { WorkspaceRootEscape } from "./read-model/errors.js";
21
+ import type { LockfileState, WorkspaceLockfileReadFailure, WorkspaceStateReadFailure } from "./service-interface.js";
22
+ type Read<A> = Effect.Effect<A, WorkspaceLockfileReadFailure, FileSystem.FileSystem | Path.Path>;
23
+ export interface LockfileReaderService {
24
+ /** The selected scope's lockfile, empty when the file is absent. */
25
+ readonly lockfile: Read<Lockfile>;
26
+ /** Probe lockfile health without mutating disk: ok | missing | invalid. */
27
+ readonly state: Effect.Effect<LockfileState, LockfileValidationError | WorkspaceRootEscape, FileSystem.FileSystem | Path.Path>;
28
+ /** The accepted entries of one type, defaulting to `{}`. */
29
+ readonly entries: <T extends InstallableExtensionType>(type: T) => Read<LockEntriesOf<T>>;
30
+ /** One accepted entry by its lock key (the workspace name, or the MCP resolution key). */
31
+ readonly entry: <T extends InstallableExtensionType>(type: T, name: string) => Read<Option.Option<LockEntryByType[T]>>;
32
+ /** Resolve a local MCP connection name to its shared accepted resolution. */
33
+ readonly mcpServerForConnection: (localName: string) => Effect.Effect<Option.Option<McpServerLockEntry>, WorkspaceStateReadFailure, FileSystem.FileSystem | Path.Path>;
34
+ }
35
+ declare const LockfileReader_base: ServiceMap.ServiceClass<LockfileReader, "@agentxm/workspace-state/LockfileReader", LockfileReaderService>;
36
+ export declare class LockfileReader extends LockfileReader_base {
37
+ }
38
+ export declare const makeLockfileReader: (location: WorkspaceLocationService, desiredState: DesiredStateReaderService) => LockfileReaderService;
39
+ export declare const LockfileReaderLive: Layer.Layer<LockfileReader, never, WorkspaceLocation | DesiredStateReader>;
40
+ export {};
41
+ //# sourceMappingURL=lockfile-reader.d.ts.map
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Lockfile reader: the selected scope's accepted resolutions — the lockfile
3
+ * health probe, the per-type entry maps, one entry by name, and the shared
4
+ * MCP resolution a local connection name accepts.
5
+ *
6
+ * @experimental This API is unstable and may change without notice.
7
+ */
8
+ import * as ServiceMap from "effect/Context";
9
+ import * as Effect from "effect/Effect";
10
+ import * as FileSystem from "effect/FileSystem";
11
+ import * as Layer from "effect/Layer";
12
+ import * as Option from "effect/Option";
13
+ import { LockfileValidationError } from "../lockfile/errors.js";
14
+ import { DesiredStateReader } from "./desired-state-reader.js";
15
+ import { lockEntries } from "./entry-accessors.js";
16
+ import { WorkspaceLocation } from "./location.js";
17
+ import { readLockfileCell } from "./state-cells.js";
18
+ export class LockfileReader extends ServiceMap.Service()("@agentxm/workspace-state/LockfileReader") {
19
+ }
20
+ export const makeLockfileReader = (location, desiredState) => {
21
+ const lockfile = readLockfileCell(location, location.runtimeDir);
22
+ return {
23
+ lockfile,
24
+ state: Effect.gen(function* () {
25
+ const fs = yield* FileSystem.FileSystem;
26
+ const exists = yield* fs
27
+ .exists(location.lockPath)
28
+ .pipe(Effect.mapError((cause) => new LockfileValidationError({ path: location.lockPath, step: "probe", cause })));
29
+ if (!exists)
30
+ return "missing";
31
+ // An unreadable or corrupt lockfile is actionable workspace state, not
32
+ // a violated invariant.
33
+ return yield* lockfile.pipe(Effect.as("ok"), Effect.catchTag([
34
+ "LockfileIoError",
35
+ "LockfileParseError",
36
+ "LockfileDecodeError",
37
+ "LockfileVersionUnsupported",
38
+ ], () => Effect.succeed("invalid")));
39
+ }).pipe(Effect.withSpan("LockfileReader.state")),
40
+ entries: (type) => lockfile.pipe(Effect.map((value) => lockEntries[type].entries(value))),
41
+ entry: (type, name) => lockfile.pipe(Effect.map((value) => lockEntries[type].entry(value, name))),
42
+ mcpServerForConnection: (localName) => Effect.gen(function* () {
43
+ const graph = yield* desiredState.graph();
44
+ const node = graph.nodes.find((candidate) => candidate.type === "mcp-server" && candidate.name === localName);
45
+ if (node === undefined || node.authority === "inline")
46
+ return Option.none();
47
+ return lockEntries["mcp-server"].entry(yield* lockfile, node.identity);
48
+ }),
49
+ };
50
+ };
51
+ export const LockfileReaderLive = Layer.effect(LockfileReader, Effect.gen(function* () {
52
+ return makeLockfileReader(yield* WorkspaceLocation, yield* DesiredStateReader);
53
+ }));
54
+ //# sourceMappingURL=lockfile-reader.js.map
@@ -2,8 +2,8 @@ import * as Schema from "effect/Schema";
2
2
  /**
3
3
  * Ephemeral result of one Rule or Hook projection reconciliation. This is the
4
4
  * extensibility axis for placement and materialization mode; grammar-level
5
- * changes belong to the managed-file ownership contract referenced by
6
- * `projection/marker-grammar.ts`.
5
+ * changes belong to the managed-file ownership contract implemented by
6
+ * `@agentxm/agent-integration` `managed-markers.ts`.
7
7
  */
8
8
  export declare const MaterializedFileTargetSchema: Schema.Struct<{
9
9
  readonly target: Schema.brand<Schema.String, "RelativePath">;
@@ -3,8 +3,8 @@ import { RelativePathSchema } from "@agentxm/extension-model/unstable/path-types
3
3
  /**
4
4
  * Ephemeral result of one Rule or Hook projection reconciliation. This is the
5
5
  * extensibility axis for placement and materialization mode; grammar-level
6
- * changes belong to the managed-file ownership contract referenced by
7
- * `projection/marker-grammar.ts`.
6
+ * changes belong to the managed-file ownership contract implemented by
7
+ * `@agentxm/agent-integration` `managed-markers.ts`.
8
8
  */
9
9
  export const MaterializedFileTargetSchema = Schema.Struct({
10
10
  target: RelativePathSchema,
@@ -0,0 +1,34 @@
1
+ /**
2
+ * The unselected scope's state, read through the same read model.
3
+ *
4
+ * A command that runs against one scope sometimes has to say something true
5
+ * about the other one — which extensions of the same name the user scope also
6
+ * configures, for instance. That read belongs to workspace state, which owns
7
+ * both layouts and both document formats; callers never open those files
8
+ * themselves.
9
+ *
10
+ * The other scope may not exist, or may be unreadable, and neither is a
11
+ * failure: the answer is simply not determined.
12
+ *
13
+ * @experimental This API is unstable and may change without notice.
14
+ */
15
+ import * as Effect from "effect/Effect";
16
+ import type * as FileSystem from "effect/FileSystem";
17
+ import * as Option from "effect/Option";
18
+ import type * as Path from "effect/Path";
19
+ import type { WorkspaceScope } from "@agentxm/extension-model/unstable/workspace-scope";
20
+ import type { Lockfile } from "../lockfile/schema.js";
21
+ import type { Settings } from "../settings/index.js";
22
+ import { WorkspaceLocation } from "./location.js";
23
+ export interface OtherScopeState {
24
+ /** The scope that was inspected: the one this workspace did not select. */
25
+ readonly scope: WorkspaceScope;
26
+ readonly settings: Settings;
27
+ readonly lockfile: Lockfile;
28
+ }
29
+ /**
30
+ * The settings and lockfile of the scope this workspace did not select, or
31
+ * `None` when that scope has no readable state.
32
+ */
33
+ export declare const readOtherScopeState: Effect.Effect<Option.Option<OtherScopeState>, never, WorkspaceLocation | FileSystem.FileSystem | Path.Path>;
34
+ //# sourceMappingURL=other-scope-reader.d.ts.map
@@ -0,0 +1,35 @@
1
+ /**
2
+ * The unselected scope's state, read through the same read model.
3
+ *
4
+ * A command that runs against one scope sometimes has to say something true
5
+ * about the other one — which extensions of the same name the user scope also
6
+ * configures, for instance. That read belongs to workspace state, which owns
7
+ * both layouts and both document formats; callers never open those files
8
+ * themselves.
9
+ *
10
+ * The other scope may not exist, or may be unreadable, and neither is a
11
+ * failure: the answer is simply not determined.
12
+ *
13
+ * @experimental This API is unstable and may change without notice.
14
+ */
15
+ import * as Effect from "effect/Effect";
16
+ import * as Option from "effect/Option";
17
+ import { WorkspaceLocation } from "./location.js";
18
+ import { readSettingsCell, readLockfileCell } from "./state-cells.js";
19
+ /**
20
+ * The settings and lockfile of the scope this workspace did not select, or
21
+ * `None` when that scope has no readable state.
22
+ */
23
+ export const readOtherScopeState = Effect.gen(function* () {
24
+ const location = yield* WorkspaceLocation;
25
+ const scope = location.scope === "project" ? "user" : "project";
26
+ const dir = scope === "user" ? location.userRuntimeDir : location.projectRuntimeDir;
27
+ const settings = yield* readSettingsCell(location, dir, scope).pipe(Effect.orElseSucceed(() => Option.none()));
28
+ if (Option.isNone(settings))
29
+ return Option.none();
30
+ const lockfile = yield* readLockfileCell(location, dir, scope).pipe(Effect.result);
31
+ return lockfile._tag === "Failure"
32
+ ? Option.none()
33
+ : Option.some({ scope, settings: settings.value, lockfile: lockfile.success });
34
+ }).pipe(Effect.withSpan("WorkspaceState.readOtherScopeState"));
35
+ //# sourceMappingURL=other-scope-reader.js.map
@@ -4,7 +4,7 @@ import * as Path from "effect/Path";
4
4
  import { type AbsolutePath } from "@agentxm/extension-model/unstable/path-types";
5
5
  import type { WorkspaceScope } from "@agentxm/extension-model/unstable/workspace-scope";
6
6
  export { AXM_DIR_NAME, USER_WORKSPACE_DIRECTORY } from "./constants.js";
7
- export interface WorkspaceLocation {
7
+ export interface LocatedWorkspace {
8
8
  readonly scope: WorkspaceScope;
9
9
  readonly path: AbsolutePath;
10
10
  readonly baseDir: AbsolutePath;
@@ -20,5 +20,5 @@ export declare const resolveUserHome: () => Effect.Effect<AbsolutePath, never, P
20
20
  export declare const resolveUserAxmHome: () => Effect.Effect<AbsolutePath, never, Path.Path>;
21
21
  export declare const resolveUserWorkspaceRoot: () => Effect.Effect<AbsolutePath, never, Path.Path>;
22
22
  export declare const getProjectRuntimeDir: (projectRoot: AbsolutePath) => Effect.Effect<AbsolutePath, never, Path.Path>;
23
- export declare const locateWorkspace: (scope: WorkspaceScope, projectRoot: AbsolutePath) => Effect.Effect<WorkspaceLocation, never, Path.Path>;
23
+ export declare const locateWorkspace: (scope: WorkspaceScope, projectRoot: AbsolutePath) => Effect.Effect<LocatedWorkspace, never, Path.Path>;
24
24
  //# sourceMappingURL=paths.d.ts.map
@@ -18,7 +18,7 @@ import * as FileSystem from "effect/FileSystem";
18
18
  import * as Layer from "effect/Layer";
19
19
  import * as Path from "effect/Path";
20
20
  import { AgentRootResolver } from "../agent-root-resolver.js";
21
- import { AgentPresenceProbe, type AgentPresenceProbeService } from "../agent-presence.js";
21
+ import { AgentPresenceProbe, type AgentPresenceProbeService } from "@agentxm/agent-integration";
22
22
  import { WorkspaceReadModelConfig } from "../service.js";
23
23
  import { type FixtureSpec, type PathEscapeError } from "./builder.js";
24
24
  /**
@@ -20,7 +20,7 @@ import * as Layer from "effect/Layer";
20
20
  import * as Path from "effect/Path";
21
21
  import { makeAbsolutePath } from "@agentxm/extension-model/unstable/path-types";
22
22
  import { AgentRootResolver, AgentRootResolverLive } from "../agent-root-resolver.js";
23
- import { AgentPresenceProbe } from "../agent-presence.js";
23
+ import { AgentPresenceProbe } from "@agentxm/agent-integration";
24
24
  import { WorkspaceReadModelConfig } from "../service.js";
25
25
  import { buildFixture } from "./builder.js";
26
26
  /**
@@ -8,7 +8,7 @@
8
8
  */
9
9
  import * as FileSystem from "effect/FileSystem";
10
10
  import * as Path from "effect/Path";
11
- import type { Skill } from "@agentxm/registry-protocol/unstable/content/skill-types";
11
+ import type { Skill } from "@agentxm/extension-content";
12
12
  import * as Effect from "effect/Effect";
13
13
  import * as Option from "effect/Option";
14
14
  import { SkillDiscoveryRootInvalid } from "../errors.js";
@@ -11,7 +11,7 @@ import * as Path from "effect/Path";
11
11
  import { AGENTS } from "@agentxm/extension-model/unstable/agents/registry";
12
12
  import { AGENT_IDS } from "@agentxm/extension-model/unstable/agents/types";
13
13
  import { parsePluginManifests } from "./plugin-manifests.js";
14
- import { parseSkillMd } from "@agentxm/registry-protocol/unstable/content/skill-content";
14
+ import { parseSkillMd } from "@agentxm/extension-content";
15
15
  import * as Array from "effect/Array";
16
16
  import * as Effect from "effect/Effect";
17
17
  import * as Option from "effect/Option";
@@ -33,8 +33,8 @@ import * as Option from "effect/Option";
33
33
  import * as Schema from "effect/Schema";
34
34
  import { decodeExtensionNameSync, ExtensionNameSchema, ExtensionTypeSchema, } from "@agentxm/extension-model/unstable/extensions/common";
35
35
  import { HandleSchema } from "@agentxm/extension-model/unstable/extensions/handle";
36
- import { MANIFEST_FILENAME_BY_TYPE } from "@agentxm/registry-protocol/unstable/publish/manifest-policy";
37
- import { parseSkillMd } from "@agentxm/registry-protocol/unstable/content/skill-content";
36
+ import { MANIFEST_FILENAME_BY_TYPE } from "@agentxm/extension-content";
37
+ import { parseSkillMd } from "@agentxm/extension-content";
38
38
  import { DISCOVERY_SKIPPED_DIRECTORIES } from "@agentxm/extension-model/unstable/discovery-walk";
39
39
  import { makeAbsolutePath } from "@agentxm/extension-model/unstable/path-types";
40
40
  import { childEntries, fileExists, filterDirectories, splitAbsolutePathSegments, } from "./fs-helpers.js";
@@ -30,7 +30,7 @@ import { AGENTS } from "@agentxm/extension-model/unstable/agents/registry";
30
30
  import { CONFIGURABLE_AGENTS_BY_ID, } from "@agentxm/extension-model/unstable/agent-capabilities";
31
31
  import { ExtensionNameSchema, } from "@agentxm/extension-model/unstable/extensions/common";
32
32
  import { makeAbsolutePath } from "@agentxm/extension-model/unstable/path-types";
33
- import { isPathSafe } from "../../../utils/path-safety.js";
33
+ import { isPathSafe } from "@agentxm/extension-model/unstable/path-types";
34
34
  const SCANNER_NAME = "mcp-config";
35
35
  /**
36
36
  * Closure helper: returns the dependency-closed scanner effect.
@@ -8,7 +8,7 @@ import * as Path from "effect/Path";
8
8
  import * as Ref from "effect/Ref";
9
9
  import * as Result from "effect/Result";
10
10
  import * as Schema from "effect/Schema";
11
- import { AgentPresenceProbe } from "./agent-presence.js";
11
+ import { AgentPresenceProbe } from "@agentxm/agent-integration";
12
12
  import { AGENTS } from "@agentxm/extension-model/unstable/agents/registry";
13
13
  import { parseExtensionFqnParts, } from "@agentxm/extension-model/unstable/extensions/common";
14
14
  import {} from "@agentxm/extension-model/unstable/extensions/handle";
@@ -7,7 +7,7 @@
7
7
  import * as Effect from "effect/Effect";
8
8
  import * as Option from "effect/Option";
9
9
  import { installableExtensionTypes, } from "@agentxm/extension-model/unstable/extensions/installable-types";
10
- import { isAxmManagedMcpEntry } from "./mcp-entry-semantics.js";
10
+ import { isAxmManagedMcpEntry } from "@agentxm/agent-integration";
11
11
  import { createDefaultSettings } from "../settings/index.js";
12
12
  import { configuredAgentLifecycleOutcomes } from "./configured-agent-outcomes.js";
13
13
  import { projectExtensionInventory, } from "./read-model/extensions/inventory.js";
@@ -9,5 +9,5 @@ import { CanonicalPathRemovalError } from "./errors.js";
9
9
  /**
10
10
  * Remove a directory if it exists.
11
11
  */
12
- export declare const removeIfExists: (fsService: FileSystem.FileSystem, dirPath: string) => Effect.Effect<void, import("./transaction.js").WorkspaceSnapshotError | CanonicalPathRemovalError, never>;
12
+ export declare const removeIfExists: (fsService: FileSystem.FileSystem, dirPath: string) => Effect.Effect<void, import("@agentxm/workspace-transactions").WorkspaceSnapshotError | CanonicalPathRemovalError, never>;
13
13
  //# sourceMappingURL=remove-if-exists.d.ts.map
@@ -6,8 +6,7 @@
6
6
  import * as FileSystem from "effect/FileSystem";
7
7
  import * as Effect from "effect/Effect";
8
8
  import { CanonicalPathRemovalError } from "./errors.js";
9
- import { protectWorkspacePath } from "./transaction.js";
10
- import { recordFootprint } from "./footprint-recorder.js";
9
+ import { protectWorkspacePath, recordFootprint } from "@agentxm/workspace-transactions";
11
10
  /**
12
11
  * Remove a directory if it exists.
13
12
  */