@agentxm/workspace-state 0.29.2 → 0.30.1
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 +3 -1
- package/dist/src/index.js +2 -0
- package/dist/src/workspace/accepted-canonical-ref.d.ts +3 -1
- package/dist/src/workspace/accepted-canonical-ref.js +9 -6
- package/dist/src/workspace/accepted-resolution-writer.js +1 -3
- package/dist/src/workspace/desired-pack-lock.d.ts +3 -2
- package/dist/src/workspace/desired-pack-lock.js +21 -20
- package/dist/src/workspace/desired-state-graph.js +4 -2
- package/dist/src/workspace/desired-state-reader.d.ts +9 -3
- package/dist/src/workspace/desired-state-reader.js +10 -3
- package/dist/src/workspace/read-model/scanners/mcp-config.js +20 -13
- package/dist/src/workspace/read-model-record-readers.js +5 -1
- package/dist/src/workspace/service-interface.d.ts +3 -4
- package/package.json +14 -16
package/dist/src/index.d.ts
CHANGED
|
@@ -67,16 +67,18 @@ export { WorkspaceLocation, type WorkspaceLocationService } from "./workspace/lo
|
|
|
67
67
|
export { SettingsReader, type SettingsReaderService } from "./workspace/settings-reader.js";
|
|
68
68
|
export { LockfileReader, type LockfileReaderService } from "./workspace/lockfile-reader.js";
|
|
69
69
|
export { readOtherScopeState, type OtherScopeState } from "./workspace/other-scope-reader.js";
|
|
70
|
-
export { DesiredStateReader, type DesiredStateReaderService, } from "./workspace/desired-state-reader.js";
|
|
70
|
+
export { DesiredStateReader, type DesiredStateReaderService, type DesiredStateGraphInputs, } from "./workspace/desired-state-reader.js";
|
|
71
71
|
export { WorkspaceRecords, type WorkspaceRecordsService } from "./workspace/workspace-records.js";
|
|
72
72
|
export { ExtensionPaths, type ExtensionPathsService } from "./workspace/extension-paths-service.js";
|
|
73
73
|
export { SettingsWriter, type SettingsWriterService } from "./workspace/settings-writer.js";
|
|
74
74
|
export { AcceptedResolutionWriter, type AcceptedResolutionWriterService, } from "./workspace/accepted-resolution-writer.js";
|
|
75
75
|
export { DesiredStateWriter, type DeclareArgsByType, type DesiredStateWriterService, } from "./workspace/desired-state-writer.js";
|
|
76
|
+
export { settingsEntries, lockEntries } from "./workspace/entry-accessors.js";
|
|
76
77
|
export type { LockEntriesOf, LockEntryByType, SettingsEntriesOf, SettingsEntryByType, } from "./workspace/entry-accessors.js";
|
|
77
78
|
export { WorkspaceMutations, 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 SetRuleArgs, type SetHookArgs, type SetKnowledgeArgs, type PackDirPath, type ExtensionTarget, type ExtensionTargetFor, type LockfileState, type SkillExtensionTarget, type PackExtensionTarget, type McpServerExtensionTarget, type SubagentExtensionTarget, type RuleExtensionTarget, type HookExtensionTarget, type KnowledgeExtensionTarget, } from "./workspace/service-interface.js";
|
|
78
79
|
export { LockfileDecodeError, LockfileIoError, LockfileParseError, LockfileVersionUnsupported, SettingsDecodeError, SettingsIoError, SettingsParseError, SkillDiscoveryRootInvalid, SubagentScanFailed, WorkspaceRootEscape, type LockfileReadError, type SettingsReadError, } from "./workspace/read-model/errors.js";
|
|
79
80
|
export { AcceptedResolutionMissing, CanonicalPathRemovalError, DesiredPackGraphIncomplete, InlineExtensionSourceMissing, InvalidAgentId, LockedSkillMissing, LockEntryEndpointConflict, LockEntryNameInvalid, LockEntrySourceMissing, LockEntrySourceTypeConflict, LockEntryUrlInvalid, PackageContentHashFailed, SettingsEntryMissing, SupersededCanonicalRemovalFailed, SymlinkCreationError, WorkspaceLayoutError, WorkspaceNotInitialized, WorkspaceSourceInvalid, } from "./workspace/errors.js";
|
|
80
81
|
export { setupScopeSupport, setupScopeSupportOutcomes, type SetupScopeSupportCategory, type SetupScopeSupportOutcome, type SetupScopeSupportReasonCode, type SetupScopeSupportStatus, } from "./workspace/setup-scope-support.js";
|
|
81
82
|
export { configuredAgentLifecycleOutcomes, EXTENSION_CONFIGURED_AGENT_POLICY, type ConfiguredAgentLifecycleState, } from "./workspace/configured-agent-outcomes.js";
|
|
83
|
+
export { lockEntrySemanticallyEqual } from "./workspace/accepted-resolution-writer.js";
|
|
82
84
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/src/index.js
CHANGED
|
@@ -85,6 +85,7 @@ export { ExtensionPaths } from "./workspace/extension-paths-service.js";
|
|
|
85
85
|
export { SettingsWriter } from "./workspace/settings-writer.js";
|
|
86
86
|
export { AcceptedResolutionWriter, } from "./workspace/accepted-resolution-writer.js";
|
|
87
87
|
export { DesiredStateWriter, } from "./workspace/desired-state-writer.js";
|
|
88
|
+
export { settingsEntries, lockEntries } from "./workspace/entry-accessors.js";
|
|
88
89
|
// TRANSITIONAL workspace mutation facade. No CLI handler composes it any
|
|
89
90
|
// more; the domain packages under packages/core still do, and it is removed
|
|
90
91
|
// when the last of them reads and writes through the narrow services above.
|
|
@@ -95,4 +96,5 @@ export { LockfileDecodeError, LockfileIoError, LockfileParseError, LockfileVersi
|
|
|
95
96
|
export { AcceptedResolutionMissing, CanonicalPathRemovalError, DesiredPackGraphIncomplete, InlineExtensionSourceMissing, InvalidAgentId, LockedSkillMissing, LockEntryEndpointConflict, LockEntryNameInvalid, LockEntrySourceMissing, LockEntrySourceTypeConflict, LockEntryUrlInvalid, PackageContentHashFailed, SettingsEntryMissing, SupersededCanonicalRemovalFailed, SymlinkCreationError, WorkspaceLayoutError, WorkspaceNotInitialized, WorkspaceSourceInvalid, } from "./workspace/errors.js";
|
|
96
97
|
export { setupScopeSupport, setupScopeSupportOutcomes, } from "./workspace/setup-scope-support.js";
|
|
97
98
|
export { configuredAgentLifecycleOutcomes, EXTENSION_CONFIGURED_AGENT_POLICY, } from "./workspace/configured-agent-outcomes.js";
|
|
99
|
+
export { lockEntrySemanticallyEqual } from "./workspace/accepted-resolution-writer.js";
|
|
98
100
|
//# sourceMappingURL=index.js.map
|
|
@@ -14,6 +14,8 @@ interface AcceptedCanonicalRefArgs {
|
|
|
14
14
|
readonly workspace: WorkspaceMutationsService;
|
|
15
15
|
readonly type: DesiredExtensionNode["type"];
|
|
16
16
|
readonly name: string;
|
|
17
|
+
/** Proposed authority when preparing a transition before publishing intent. */
|
|
18
|
+
readonly desired?: DesiredExtensionNode;
|
|
17
19
|
}
|
|
18
20
|
/** Every failure the accepted-canonical reconstruction functions can produce. */
|
|
19
21
|
export type AcceptedCanonicalRefError = WorkspaceStateReadFailure | LockEntryToRefError | AcceptedResolutionMissing | InlineExtensionSourceMissing | WorkspaceSourceInvalid | PathTraversalDetected | PackageContentHashFailed;
|
|
@@ -50,7 +52,7 @@ export declare const acceptedLockedResolutionRef: (args: AcceptedCanonicalRefArg
|
|
|
50
52
|
* even when its canonical materialization is absent or divergent.
|
|
51
53
|
*/
|
|
52
54
|
export declare const acceptedResolutionRef: (args: AcceptedCanonicalRefArgs) => Effect.Effect<Option.Option<ExtensionRef>, AcceptedCanonicalRefError, FileSystem.FileSystem | Path.Path>;
|
|
53
|
-
export declare const acceptedCanonicalObservation: ({ workspace, type, name, }: AcceptedCanonicalRefArgs) => Effect.Effect<Option.Option<AcceptedCanonicalObservation>, AcceptedCanonicalRefError, FileSystem.FileSystem | Path.Path>;
|
|
55
|
+
export declare const acceptedCanonicalObservation: ({ workspace, type, name, desired: proposed, }: AcceptedCanonicalRefArgs) => Effect.Effect<Option.Option<AcceptedCanonicalObservation>, AcceptedCanonicalRefError, FileSystem.FileSystem | Path.Path>;
|
|
54
56
|
export declare const usableAcceptedCanonicalObservation: (args: AcceptedCanonicalRefArgs) => Effect.Effect<Option.Option<UsableAcceptedCanonicalObservation>, AcceptedCanonicalRefError, FileSystem.FileSystem | Path.Path>;
|
|
55
57
|
export declare const usableAcceptedCanonical: (args: AcceptedCanonicalRefArgs) => Effect.Effect<Option.Option<UsableAcceptedCanonical>, AcceptedCanonicalRefError, FileSystem.FileSystem | Path.Path>;
|
|
56
58
|
export declare const usableAcceptedCanonicalRef: (args: AcceptedCanonicalRefArgs) => Effect.Effect<Option.Option<ExtensionRef>, AcceptedCanonicalRefError, FileSystem.FileSystem | Path.Path>;
|
|
@@ -188,16 +188,16 @@ const refForDesired = (workspace, desired) => Effect.gen(function* () {
|
|
|
188
188
|
* even when its canonical materialization is absent or divergent.
|
|
189
189
|
*/
|
|
190
190
|
export const acceptedResolutionRef = (args) => Effect.gen(function* () {
|
|
191
|
-
const
|
|
192
|
-
|
|
191
|
+
const desired = args.desired ??
|
|
192
|
+
(yield* args.workspace.getDesiredStateGraph()).nodes.find((node) => node.type === args.type && node.name === args.name);
|
|
193
193
|
if (desired === undefined || desired.identity.startsWith("workspace:")) {
|
|
194
194
|
return Option.none();
|
|
195
195
|
}
|
|
196
196
|
return yield* acceptedLockedResolutionRef(args);
|
|
197
197
|
});
|
|
198
|
-
export const acceptedCanonicalObservation = ({ workspace, type, name, }) => Effect.gen(function* () {
|
|
199
|
-
const
|
|
200
|
-
|
|
198
|
+
export const acceptedCanonicalObservation = ({ workspace, type, name, desired: proposed, }) => Effect.gen(function* () {
|
|
199
|
+
const desired = proposed ??
|
|
200
|
+
(yield* workspace.getDesiredStateGraph()).nodes.find((node) => node.type === type && node.name === name);
|
|
201
201
|
if (desired === undefined)
|
|
202
202
|
return Option.none();
|
|
203
203
|
const accepted = yield* getAcceptedResolution(workspace, type, name);
|
|
@@ -223,7 +223,10 @@ export const usableAcceptedCanonical = (args) => Effect.gen(function* () {
|
|
|
223
223
|
if (Option.isNone(canonical))
|
|
224
224
|
return Option.none();
|
|
225
225
|
const ref = yield* refForDesired(args.workspace, canonical.value.desired);
|
|
226
|
-
|
|
226
|
+
// A usable local acquisition is the accepted copy, even if the original
|
|
227
|
+
// directory has changed or disappeared. Keep sourcePath as its identity.
|
|
228
|
+
const retainedRef = ref.refType === "local" ? { ...ref, location: canonical.value.observation.path } : ref;
|
|
229
|
+
return Option.some({ ...canonical.value, ref: retainedRef });
|
|
227
230
|
});
|
|
228
231
|
export const usableAcceptedCanonicalRef = (args) => usableAcceptedCanonical(args).pipe(Effect.map(Option.map((canonical) => canonical.ref)));
|
|
229
232
|
//# sourceMappingURL=accepted-canonical-ref.js.map
|
|
@@ -37,8 +37,6 @@ export const stableCompare = (left, right) => JSON.stringify(normalizeForStableC
|
|
|
37
37
|
export const lockEntrySemanticallyEqual = (current, next) => current !== undefined && stableCompare(current, next);
|
|
38
38
|
/** Keep the recorded object when the replacement carries the same facts. */
|
|
39
39
|
export const preserveAcceptedResolutionOnNoop = (current, next) => (lockEntrySemanticallyEqual(current, next) && current !== undefined ? current : next);
|
|
40
|
-
/** Types whose semantically unchanged resolution skips the commit entirely. */
|
|
41
|
-
const skipsUnchangedCommit = (type) => type === "skill" || type === "subagent";
|
|
42
40
|
export const makeAcceptedResolutionWriter = (location, mutex) => {
|
|
43
41
|
const current = readLockfileCell(location, location.runtimeDir);
|
|
44
42
|
const commit = (base, next) => commitLockfileSnapshotUpdateAtPath(location.lockPath, base, next);
|
|
@@ -48,7 +46,7 @@ export const makeAcceptedResolutionWriter = (location, mutex) => {
|
|
|
48
46
|
const lockfile = yield* current;
|
|
49
47
|
const accessor = lockEntries[type];
|
|
50
48
|
const previous = accessor.entries(lockfile)[key];
|
|
51
|
-
if (
|
|
49
|
+
if (lockEntrySemanticallyEqual(previous, entry))
|
|
52
50
|
return;
|
|
53
51
|
yield* commit(lockfile, accessor.set(lockfile, key, preserveAcceptedResolutionOnNoop(previous, entry)));
|
|
54
52
|
})).pipe(Effect.withSpan("AcceptedResolutionWriter.setAccepted")),
|
|
@@ -2,17 +2,18 @@ import * as Effect from "effect/Effect";
|
|
|
2
2
|
import * as FileSystem from "effect/FileSystem";
|
|
3
3
|
import * as Path from "effect/Path";
|
|
4
4
|
import type { Lockfile } from "../lockfile/schema.js";
|
|
5
|
-
import { type DesiredStateGraph } from "./desired-state-graph.js";
|
|
5
|
+
import { type DesiredStateGraph, type ProspectivePackRef } from "./desired-state-graph.js";
|
|
6
6
|
import type { WorkspaceLayout } from "./layout.js";
|
|
7
7
|
interface ValidateDesiredPackLockArgs {
|
|
8
8
|
readonly graph: DesiredStateGraph;
|
|
9
9
|
readonly lockfile: Lockfile;
|
|
10
10
|
readonly layout: WorkspaceLayout;
|
|
11
|
+
readonly prospectivePacks?: ReadonlyArray<ProspectivePackRef>;
|
|
11
12
|
}
|
|
12
13
|
/**
|
|
13
14
|
* Authorize enabled external Pack manifests against their accepted lock row.
|
|
14
15
|
* Workspace-authored Pack manifests are desired authority and need no lock row.
|
|
15
16
|
*/
|
|
16
|
-
export declare const validateDesiredPackLock: ({ graph, lockfile, layout, }: ValidateDesiredPackLockArgs) => Effect.Effect<DesiredStateGraph, never, FileSystem.FileSystem | Path.Path>;
|
|
17
|
+
export declare const validateDesiredPackLock: ({ graph, lockfile, layout, prospectivePacks, }: ValidateDesiredPackLockArgs) => Effect.Effect<DesiredStateGraph, never, FileSystem.FileSystem | Path.Path>;
|
|
17
18
|
export {};
|
|
18
19
|
//# sourceMappingURL=desired-pack-lock.d.ts.map
|
|
@@ -52,7 +52,7 @@ const decodeManifest = Schema.decodeUnknownSync(PackManifestSchema, {
|
|
|
52
52
|
* Authorize enabled external Pack manifests against their accepted lock row.
|
|
53
53
|
* Workspace-authored Pack manifests are desired authority and need no lock row.
|
|
54
54
|
*/
|
|
55
|
-
export const validateDesiredPackLock = ({ graph, lockfile, layout, }) => Effect.gen(function* () {
|
|
55
|
+
export const validateDesiredPackLock = ({ graph, lockfile, layout, prospectivePacks = [], }) => Effect.gen(function* () {
|
|
56
56
|
const fs = yield* FileSystem.FileSystem;
|
|
57
57
|
const path = yield* Path.Path;
|
|
58
58
|
const problems = [];
|
|
@@ -82,24 +82,25 @@ export const validateDesiredPackLock = ({ graph, lockfile, layout, }) => Effect.
|
|
|
82
82
|
continue;
|
|
83
83
|
}
|
|
84
84
|
const manifestPath = path.join(computePackPathsForLayout(path.join, layout, entry.sourceName, identity.owner, identity.name).canonicalPath, PACK_MANIFEST_FILENAME);
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
85
|
+
const prospective = prospectivePacks.find((ref) => ref.owner === identity.owner && ref.pack.name === identity.name);
|
|
86
|
+
const observedManifest = prospective === undefined
|
|
87
|
+
? yield* Effect.gen(function* () {
|
|
88
|
+
const readResult = yield* Effect.result(fs.readFileString(manifestPath));
|
|
89
|
+
if (Result.isFailure(readResult))
|
|
90
|
+
return undefined;
|
|
91
|
+
const decoded = Result.try({
|
|
92
|
+
try: () => decodeManifest(JSON.parse(readResult.success)),
|
|
93
|
+
catch: () => undefined,
|
|
94
|
+
});
|
|
95
|
+
return Result.isSuccess(decoded) ? decoded.success : undefined;
|
|
96
|
+
})
|
|
97
|
+
: {
|
|
98
|
+
owner: prospective.owner,
|
|
99
|
+
type: "pack",
|
|
100
|
+
name: prospective.pack.name,
|
|
101
|
+
version: prospective.version,
|
|
102
|
+
dependencies: prospective.pack.dependencies,
|
|
103
|
+
};
|
|
103
104
|
const observedContentIdentity = observedManifest === undefined
|
|
104
105
|
? undefined
|
|
105
106
|
: computePackManifestContentIdentity(observedManifest);
|
|
@@ -109,7 +110,7 @@ export const validateDesiredPackLock = ({ graph, lockfile, layout, }) => Effect.
|
|
|
109
110
|
type: "pack-manifest-content-mismatch",
|
|
110
111
|
pack: node.identity,
|
|
111
112
|
path: manifestPath,
|
|
112
|
-
status: "changed",
|
|
113
|
+
status: observedManifest === undefined ? "missing" : "changed",
|
|
113
114
|
acceptedVersion: entry.resolvedVersion,
|
|
114
115
|
acceptedContentIdentity: entry.manifestContentIdentity,
|
|
115
116
|
...(observedManifest === undefined || observedContentIdentity === undefined
|
|
@@ -242,6 +242,8 @@ export const buildDesiredStateGraph = ({ baseDir, settings, layout, prospectiveP
|
|
|
242
242
|
});
|
|
243
243
|
const workspacePack = isWorkspaceSourceLocator(entry.source);
|
|
244
244
|
const configuredRegistrySource = registryLocator(entry.source)?.sourceName ?? "agentxm";
|
|
245
|
+
if (entry.enabled === false)
|
|
246
|
+
continue;
|
|
245
247
|
const manifestPath = path.join(layout === undefined
|
|
246
248
|
? path.join(baseDir, workspacePack
|
|
247
249
|
? configuredAuthoredDirectory(settings, "pack")
|
|
@@ -308,7 +310,7 @@ export const buildDesiredStateGraph = ({ baseDir, settings, layout, prospectiveP
|
|
|
308
310
|
identity: dependencyIdentity,
|
|
309
311
|
authority: "sourced",
|
|
310
312
|
source: `${fqn}@${constraint}`,
|
|
311
|
-
enabled:
|
|
313
|
+
enabled: true,
|
|
312
314
|
constraint,
|
|
313
315
|
origin: {
|
|
314
316
|
type: "pack",
|
|
@@ -316,7 +318,7 @@ export const buildDesiredStateGraph = ({ baseDir, settings, layout, prospectiveP
|
|
|
316
318
|
manifestPath: path.relative(baseDir, manifestPath),
|
|
317
319
|
source: fqn,
|
|
318
320
|
constraint,
|
|
319
|
-
enabled:
|
|
321
|
+
enabled: true,
|
|
320
322
|
},
|
|
321
323
|
});
|
|
322
324
|
}
|
|
@@ -11,15 +11,21 @@ import type * as FileSystem from "effect/FileSystem";
|
|
|
11
11
|
import * as Layer from "effect/Layer";
|
|
12
12
|
import type * as Path from "effect/Path";
|
|
13
13
|
import { type DesiredStateGraph, type ProspectivePackRef } from "./desired-state-graph.js";
|
|
14
|
+
import type { Settings } from "../settings/index.js";
|
|
15
|
+
import type { Lockfile } from "../lockfile/index.js";
|
|
14
16
|
import { DesiredPackGraphIncomplete } from "./errors.js";
|
|
15
17
|
import { WorkspaceLocation, type WorkspaceLocationService } from "./location.js";
|
|
16
18
|
import type { ExtensionTarget, WorkspaceStateReadFailure } from "./service-interface.js";
|
|
17
19
|
import { SettingsReader, type SettingsReaderService } from "./settings-reader.js";
|
|
20
|
+
/** Authoritative inputs for evaluating a candidate without publishing it. */
|
|
21
|
+
export interface DesiredStateGraphInputs {
|
|
22
|
+
readonly settings?: Settings;
|
|
23
|
+
readonly acceptedResolutions?: Lockfile;
|
|
24
|
+
readonly prospectivePacks?: ReadonlyArray<ProspectivePackRef>;
|
|
25
|
+
}
|
|
18
26
|
export interface DesiredStateReaderService {
|
|
19
27
|
/** Build desired extension state from settings and installed or prospective Pack manifests. */
|
|
20
|
-
readonly graph: (options?:
|
|
21
|
-
readonly prospectivePacks?: ReadonlyArray<ProspectivePackRef>;
|
|
22
|
-
}) => Effect.Effect<DesiredStateGraph, WorkspaceStateReadFailure, FileSystem.FileSystem | Path.Path>;
|
|
28
|
+
readonly graph: (options?: DesiredStateGraphInputs) => Effect.Effect<DesiredStateGraph, WorkspaceStateReadFailure, FileSystem.FileSystem | Path.Path>;
|
|
23
29
|
/** Whether an installed Pack's dependency maps reference the target. */
|
|
24
30
|
readonly isRequiredByInstalledPack: (target: ExtensionTarget) => Effect.Effect<boolean, WorkspaceStateReadFailure | DesiredPackGraphIncomplete, FileSystem.FileSystem | Path.Path>;
|
|
25
31
|
}
|
|
@@ -19,7 +19,7 @@ export class DesiredStateReader extends ServiceMap.Service()("@agentxm/workspace
|
|
|
19
19
|
}
|
|
20
20
|
export const makeDesiredStateReader = (location, settings) => {
|
|
21
21
|
const graph = (options) => Effect.gen(function* () {
|
|
22
|
-
const current = yield* settings.settings;
|
|
22
|
+
const current = options?.settings ?? (yield* settings.settings);
|
|
23
23
|
const configuredSources = yield* settings.configuredSources;
|
|
24
24
|
const layout = yield* Ref.get(location.layout);
|
|
25
25
|
const registryAuthorities = Object.fromEntries(configuredSources.flatMap((source) => source.type === "registry" ? [[source.name, source.location]] : []));
|
|
@@ -32,8 +32,15 @@ export const makeDesiredStateReader = (location, settings) => {
|
|
|
32
32
|
? {}
|
|
33
33
|
: { prospectivePacks: options.prospectivePacks }),
|
|
34
34
|
});
|
|
35
|
-
const lockfile = yield* readLockfileCell(location, location.runtimeDir);
|
|
36
|
-
return yield* validateDesiredPackLock({
|
|
35
|
+
const lockfile = options?.acceptedResolutions ?? (yield* readLockfileCell(location, location.runtimeDir));
|
|
36
|
+
return yield* validateDesiredPackLock({
|
|
37
|
+
graph: built,
|
|
38
|
+
lockfile,
|
|
39
|
+
layout,
|
|
40
|
+
...(options?.prospectivePacks === undefined
|
|
41
|
+
? {}
|
|
42
|
+
: { prospectivePacks: options.prospectivePacks }),
|
|
43
|
+
});
|
|
37
44
|
}).pipe(Effect.withSpan("DesiredStateReader.graph"));
|
|
38
45
|
return {
|
|
39
46
|
graph,
|
|
@@ -24,7 +24,9 @@
|
|
|
24
24
|
import * as Effect from "effect/Effect";
|
|
25
25
|
import * as Option from "effect/Option";
|
|
26
26
|
import * as Schema from "effect/Schema";
|
|
27
|
-
import { parse } from "jsonc-parser";
|
|
27
|
+
import { parse as parseJson } from "jsonc-parser";
|
|
28
|
+
import { parse as parseToml } from "smol-toml";
|
|
29
|
+
import { parse as parseYaml } from "yaml";
|
|
28
30
|
import { getHome } from "../../../utils/environment.js";
|
|
29
31
|
import { AGENTS } from "@agentxm/extension-model/unstable/agents/registry";
|
|
30
32
|
import { CONFIGURABLE_AGENTS_BY_ID, } from "@agentxm/extension-model/unstable/agent-capabilities";
|
|
@@ -61,7 +63,18 @@ const extractServers = (decoded, serversKey) => !isRecord(decoded[serversKey])
|
|
|
61
63
|
const decodedName = decodeExtensionNameOption(name);
|
|
62
64
|
return Option.isNone(decodedName) ? [] : [{ name: decodedName.value, config }];
|
|
63
65
|
});
|
|
64
|
-
const
|
|
66
|
+
const parseMcpConfig = (raw, format) => {
|
|
67
|
+
if (format === "toml")
|
|
68
|
+
return parseToml(raw);
|
|
69
|
+
if (format === "yaml")
|
|
70
|
+
return parseYaml(raw);
|
|
71
|
+
const errors = [];
|
|
72
|
+
const value = parseJson(raw, errors, { allowTrailingComma: true });
|
|
73
|
+
if (errors.length > 0)
|
|
74
|
+
throw errors;
|
|
75
|
+
return value;
|
|
76
|
+
};
|
|
77
|
+
const readMcpConfig = (fs, diagnostics, filePath, format) => Effect.gen(function* () {
|
|
65
78
|
const exists = yield* Effect.result(fs.exists(filePath));
|
|
66
79
|
if (exists._tag === "Failure") {
|
|
67
80
|
yield* diagnostics.append({
|
|
@@ -85,19 +98,13 @@ const readMcpConfig = (fs, diagnostics, filePath) => Effect.gen(function* () {
|
|
|
85
98
|
return Option.none();
|
|
86
99
|
}
|
|
87
100
|
const parsed = yield* Effect.result(Effect.try({
|
|
88
|
-
try: () =>
|
|
89
|
-
const errors = [];
|
|
90
|
-
const value = parse(read.success, errors, { allowTrailingComma: true });
|
|
91
|
-
if (errors.length > 0)
|
|
92
|
-
throw errors;
|
|
93
|
-
return value;
|
|
94
|
-
},
|
|
101
|
+
try: () => parseMcpConfig(read.success, format),
|
|
95
102
|
catch: (cause) => ({ cause }),
|
|
96
103
|
}));
|
|
97
104
|
if (parsed._tag === "Failure") {
|
|
98
105
|
yield* diagnostics.append({
|
|
99
106
|
source: "scanner",
|
|
100
|
-
message: `${SCANNER_NAME}: cannot parse
|
|
107
|
+
message: `${SCANNER_NAME}: cannot parse ${format.toUpperCase()} at ${filePath}`,
|
|
101
108
|
path: filePath,
|
|
102
109
|
code: "scanner-parse",
|
|
103
110
|
});
|
|
@@ -115,11 +122,11 @@ const readMcpConfig = (fs, diagnostics, filePath) => Effect.gen(function* () {
|
|
|
115
122
|
}
|
|
116
123
|
return Option.some(decoded.success);
|
|
117
124
|
});
|
|
118
|
-
const readMcpConfigCached = (cache, fs, diagnostics, filePath) => {
|
|
125
|
+
const readMcpConfigCached = (cache, fs, diagnostics, filePath, format) => {
|
|
119
126
|
const existing = cache.get(filePath);
|
|
120
127
|
if (existing !== undefined)
|
|
121
128
|
return Effect.succeed(existing);
|
|
122
|
-
return readMcpConfig(fs, diagnostics, filePath).pipe(Effect.tap((decoded) => Effect.sync(() => {
|
|
129
|
+
return readMcpConfig(fs, diagnostics, filePath, format).pipe(Effect.tap((decoded) => Effect.sync(() => {
|
|
123
130
|
cache.set(filePath, decoded);
|
|
124
131
|
})));
|
|
125
132
|
};
|
|
@@ -183,7 +190,7 @@ const scanMcpSurface = (deps, plan, cache) => Effect.gen(function* () {
|
|
|
183
190
|
const filePathOpt = yield* resolveMcpConfigTargetPath(deps, plan.target);
|
|
184
191
|
if (Option.isNone(filePathOpt))
|
|
185
192
|
return [];
|
|
186
|
-
const decoded = yield* readMcpConfigCached(cache, fs, diagnostics, filePathOpt.value);
|
|
193
|
+
const decoded = yield* readMcpConfigCached(cache, fs, diagnostics, filePathOpt.value, plan.target.format);
|
|
187
194
|
if (Option.isNone(decoded))
|
|
188
195
|
return [];
|
|
189
196
|
const servers = extractServers(decoded.value, plan.serversKey);
|
|
@@ -79,7 +79,11 @@ export const makeReadModelRecordReaders = (args) => {
|
|
|
79
79
|
lifecycle: row.installationOrigin._tag === "direct" ? "configured" : "implicit",
|
|
80
80
|
enabled: row.activation === "enabled",
|
|
81
81
|
installed: row.actual.length > 0,
|
|
82
|
-
agents:
|
|
82
|
+
agents: row.key.type === "mcp-server"
|
|
83
|
+
? defaultAgents
|
|
84
|
+
: observedAgents.length === 0
|
|
85
|
+
? defaultAgents
|
|
86
|
+
: observedAgents,
|
|
83
87
|
origins: observations.origins,
|
|
84
88
|
paths: observations.paths,
|
|
85
89
|
};
|
|
@@ -28,7 +28,8 @@ import type { ReadModelRecordRow } from "./read-model-record-types.js";
|
|
|
28
28
|
import type { WorkspaceScope } from "@agentxm/extension-model/unstable/workspace-scope";
|
|
29
29
|
import type { ExtensionInventory } from "./read-model/extensions/inventory.js";
|
|
30
30
|
import type { ResolvedKnowledgeDiscoveryConfig } from "../knowledge/discovery-config.js";
|
|
31
|
-
import type {
|
|
31
|
+
import type { DesiredStateGraphInputs } from "./desired-state-reader.js";
|
|
32
|
+
import type { DesiredStateGraph } from "./desired-state-graph.js";
|
|
32
33
|
import type { AbsolutePath } from "@agentxm/extension-model/unstable/path-types";
|
|
33
34
|
import type { WorkspaceLayout } from "./layout.js";
|
|
34
35
|
import type { ExtensionPathSource } from "./extension-paths.js";
|
|
@@ -211,9 +212,7 @@ export interface WorkspaceMutationsService {
|
|
|
211
212
|
/** Probe lockfile state for policy decisions: ok | missing | invalid. */
|
|
212
213
|
readonly getLockfileState: () => Effect.Effect<LockfileState, LockfileValidationError | WorkspaceRootEscape>;
|
|
213
214
|
/** Build desired extension state from settings and installed or prospective Pack manifests. */
|
|
214
|
-
readonly getDesiredStateGraph: (options?:
|
|
215
|
-
readonly prospectivePacks?: ReadonlyArray<ProspectivePackRef>;
|
|
216
|
-
}) => Effect.Effect<DesiredStateGraph, WorkspaceStateReadFailure>;
|
|
215
|
+
readonly getDesiredStateGraph: (options?: DesiredStateGraphInputs) => Effect.Effect<DesiredStateGraph, WorkspaceStateReadFailure>;
|
|
217
216
|
/** Merged sources from project, user-scope, and built-in defaults. Cached per workspace lifetime. */
|
|
218
217
|
readonly getConfiguredSources: () => Effect.Effect<ReadonlyArray<SourceHostConfig>, WorkspaceSettingsReadFailure>;
|
|
219
218
|
/** Lookup a source by name from the merged sources list. */
|
package/package.json
CHANGED
|
@@ -4,19 +4,20 @@
|
|
|
4
4
|
"url": "https://github.com/agentxm/axm/issues"
|
|
5
5
|
},
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"@agentxm/agent-integration": "^0.
|
|
8
|
-
"@agentxm/extension-content": "^0.
|
|
9
|
-
"@agentxm/extension-model": "^0.
|
|
10
|
-
"@agentxm/registry-protocol": "^0.
|
|
11
|
-
"@agentxm/workspace-transactions": "^0.
|
|
7
|
+
"@agentxm/agent-integration": "^0.30.1",
|
|
8
|
+
"@agentxm/extension-content": "^0.30.1",
|
|
9
|
+
"@agentxm/extension-model": "^0.30.1",
|
|
10
|
+
"@agentxm/registry-protocol": "^0.30.1",
|
|
11
|
+
"@agentxm/workspace-transactions": "^0.30.1",
|
|
12
12
|
"effect": "4.0.0-rc.115",
|
|
13
13
|
"jsonc-parser": "^3.3.1",
|
|
14
14
|
"semver": "^7.8.5",
|
|
15
|
+
"smol-toml": "^1.7.1",
|
|
15
16
|
"yaml": "^2.9.0"
|
|
16
17
|
},
|
|
17
18
|
"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.",
|
|
18
19
|
"devDependencies": {
|
|
19
|
-
"@agentxm/specification-metadata": "^0.
|
|
20
|
+
"@agentxm/specification-metadata": "^0.30.1",
|
|
20
21
|
"@effect/platform-node": "4.0.0-rc.115",
|
|
21
22
|
"@effect/vitest": "4.0.0-rc.115",
|
|
22
23
|
"@fast-check/vitest": "^0.5.0",
|
|
@@ -30,19 +31,16 @@
|
|
|
30
31
|
},
|
|
31
32
|
"exports": {
|
|
32
33
|
".": {
|
|
33
|
-
"
|
|
34
|
-
"default": "./dist/src/index.js"
|
|
35
|
-
"types": "./dist/src/index.d.ts"
|
|
34
|
+
"types": "./dist/src/index.d.ts",
|
|
35
|
+
"default": "./dist/src/index.js"
|
|
36
36
|
},
|
|
37
37
|
"./live": {
|
|
38
|
-
"
|
|
39
|
-
"default": "./dist/src/live.js"
|
|
40
|
-
"types": "./dist/src/live.d.ts"
|
|
38
|
+
"types": "./dist/src/live.d.ts",
|
|
39
|
+
"default": "./dist/src/live.js"
|
|
41
40
|
},
|
|
42
41
|
"./testing": {
|
|
43
|
-
"
|
|
44
|
-
"default": "./dist/src/testing.js"
|
|
45
|
-
"types": "./dist/src/testing.d.ts"
|
|
42
|
+
"types": "./dist/src/testing.d.ts",
|
|
43
|
+
"default": "./dist/src/testing.js"
|
|
46
44
|
}
|
|
47
45
|
},
|
|
48
46
|
"files": [
|
|
@@ -65,5 +63,5 @@
|
|
|
65
63
|
},
|
|
66
64
|
"sideEffects": false,
|
|
67
65
|
"type": "module",
|
|
68
|
-
"version": "0.
|
|
66
|
+
"version": "0.30.1"
|
|
69
67
|
}
|