@agentxm/workspace-configuration 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.
- package/dist/src/errors.d.ts +29 -0
- package/dist/src/errors.js +68 -0
- package/dist/src/index.d.ts +17 -12
- package/dist/src/index.js +28 -11
- package/dist/src/inline-mcp/add-inline-mcp-server.d.ts +63 -0
- package/dist/src/inline-mcp/add-inline-mcp-server.js +253 -0
- package/dist/src/{inline-mcp.d.ts → inline-mcp/definition.d.ts} +3 -3
- package/dist/src/{inline-mcp.js → inline-mcp/definition.js} +2 -2
- package/dist/src/instructions/manage-instructions.d.ts +125 -0
- package/dist/src/instructions/manage-instructions.js +361 -0
- package/dist/src/mcp-import/apply.d.ts +33 -0
- package/dist/src/{mcp-import.js → mcp-import/apply.js} +8 -50
- package/dist/src/mcp-import/import-mcp-servers.d.ts +49 -0
- package/dist/src/mcp-import/import-mcp-servers.js +117 -0
- package/dist/src/{mcp-import-preflight.d.ts → mcp-import/preflight.d.ts} +1 -1
- package/dist/src/{mcp-import-preflight.js → mcp-import/preflight.js} +2 -2
- package/dist/src/membership/agent-lifecycle.d.ts +20 -0
- package/dist/src/membership/agent-lifecycle.js +33 -0
- package/dist/src/membership/atomic-membership.d.ts +41 -0
- package/dist/src/membership/atomic-membership.js +125 -0
- package/dist/src/membership/configure-agents.d.ts +197 -0
- package/dist/src/membership/configure-agents.js +395 -0
- package/dist/src/membership/validate-agent-ids.d.ts +16 -0
- package/dist/src/membership/validate-agent-ids.js +85 -0
- package/dist/src/{initialization-interaction.d.ts → setup/initialization-interaction.d.ts} +1 -1
- package/dist/src/{initialization.d.ts → setup/initialization.d.ts} +11 -11
- package/dist/src/{initialization.js → setup/initialization.js} +3 -3
- package/dist/src/setup/setup-workspace.d.ts +264 -0
- package/dist/src/setup/setup-workspace.js +512 -0
- package/dist/src/testing.d.ts +95 -4
- package/dist/src/testing.js +215 -4
- package/package.json +11 -9
- package/dist/src/instruction-reconciliation.d.ts +0 -57
- package/dist/src/instruction-reconciliation.js +0 -93
- package/dist/src/mcp-import.d.ts +0 -40
- package/dist/src/membership.d.ts +0 -29
- package/dist/src/membership.js +0 -162
- /package/dist/src/{initialization-interaction.js → setup/initialization-interaction.js} +0 -0
package/dist/src/testing.js
CHANGED
|
@@ -1,9 +1,220 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* @agentxm/workspace-configuration deterministic fixtures and ports.
|
|
3
|
+
*
|
|
4
|
+
* A throwaway workspace with settings, lockfile, and agent-native files
|
|
5
|
+
* written as the product writes them, plus every service a configuration use
|
|
6
|
+
* case reads or writes through: the workspace state and its transaction
|
|
7
|
+
* scope, the projection capability, the rule manager, and the plan pipeline's
|
|
8
|
+
* per-invocation services with a recording interaction port. Production
|
|
9
|
+
* source never imports this module.
|
|
5
10
|
*
|
|
6
11
|
* @experimental This API is unstable and may change without notice.
|
|
7
12
|
*/
|
|
8
|
-
|
|
13
|
+
import * as fs from "node:fs";
|
|
14
|
+
import * as os from "node:os";
|
|
15
|
+
import * as nodePath from "node:path";
|
|
16
|
+
import * as ConfigProvider from "effect/ConfigProvider";
|
|
17
|
+
import * as Effect from "effect/Effect";
|
|
18
|
+
import * as Layer from "effect/Layer";
|
|
19
|
+
import * as Option from "effect/Option";
|
|
20
|
+
import * as HttpClient from "effect/unstable/http/HttpClient";
|
|
21
|
+
import { AgentExecutableResolver } from "@agentxm/agent-integration";
|
|
22
|
+
import { SourceHostProviders } from "@agentxm/extension-sources";
|
|
23
|
+
import { decodeAbsolutePathSync } from "@agentxm/extension-model/unstable/path-types";
|
|
24
|
+
import { RuleManagerLive } from "@agentxm/extension-materialization/live";
|
|
25
|
+
import { PlanInvocationTest, ResolvePlanInteractionTest, } from "@agentxm/workspace-operations/testing";
|
|
26
|
+
import { ProjectionParticipants, emptyProjectionParticipants } from "@agentxm/workspace-projection";
|
|
27
|
+
import { CodingAgentRepositoryLive, NativeWriteAuthorityLive, WorkspaceCatalogLive, WorkspaceInvariantFactsLive, } from "@agentxm/workspace-projection/live";
|
|
28
|
+
import { layer as WorkspaceLayerLive } from "@agentxm/workspace-state/live";
|
|
29
|
+
import { WorkspaceInitializationInteractionTest, } from "./setup/initialization-interaction.js";
|
|
30
|
+
export { WorkspaceInitializationInteractionTest };
|
|
31
|
+
/**
|
|
32
|
+
* A throwaway workspace with every service a configuration use case needs
|
|
33
|
+
* over it, and a pinned user home so a project-scope run can be shown to
|
|
34
|
+
* leave the user scope alone.
|
|
35
|
+
*/
|
|
36
|
+
export const makeConfigurationFixture = (options = {}) => {
|
|
37
|
+
const scope = options.scope ?? "project";
|
|
38
|
+
const root = fs.realpathSync(fs.mkdtempSync(nodePath.join(os.tmpdir(), "axm-configuration-")));
|
|
39
|
+
const home = fs.realpathSync(fs.mkdtempSync(nodePath.join(os.tmpdir(), "axm-configuration-home-")));
|
|
40
|
+
const workspaceRoot = scope === "user" ? nodePath.join(home, ".axm", "workspace") : root;
|
|
41
|
+
fs.mkdirSync(nodePath.join(root, ".axm"), { recursive: true });
|
|
42
|
+
fs.mkdirSync(nodePath.join(home, ".axm", "workspace"), { recursive: true });
|
|
43
|
+
const writeUnder = (base) => (relativePath, contents) => {
|
|
44
|
+
const file = nodePath.join(base, relativePath);
|
|
45
|
+
fs.mkdirSync(nodePath.dirname(file), { recursive: true });
|
|
46
|
+
fs.writeFileSync(file, contents);
|
|
47
|
+
};
|
|
48
|
+
const writeFile = writeUnder(root);
|
|
49
|
+
const writeHomeFile = writeUnder(home);
|
|
50
|
+
const readFile = (relativePath) => fs.readFileSync(nodePath.join(root, relativePath), "utf8");
|
|
51
|
+
const exists = (relativePath) => fs.existsSync(nodePath.join(root, relativePath));
|
|
52
|
+
/** Every file, symlink, and directory under a root, so purity can be proven. */
|
|
53
|
+
const snapshotUnder = (base) => {
|
|
54
|
+
const entries = [];
|
|
55
|
+
const walk = (directory) => {
|
|
56
|
+
for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
|
|
57
|
+
const absolute = nodePath.join(directory, entry.name);
|
|
58
|
+
const relative = nodePath.relative(base, absolute);
|
|
59
|
+
if (entry.isSymbolicLink()) {
|
|
60
|
+
entries.push([relative, `symlink:${fs.readlinkSync(absolute)}`]);
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (entry.isDirectory()) {
|
|
64
|
+
entries.push([relative, "directory"]);
|
|
65
|
+
walk(absolute);
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
entries.push([relative, fs.readFileSync(absolute, "utf8")]);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
walk(base);
|
|
72
|
+
return entries.sort((left, right) => left[0].localeCompare(right[0]));
|
|
73
|
+
};
|
|
74
|
+
if (options.settings !== undefined) {
|
|
75
|
+
fs.writeFileSync(nodePath.join(workspaceRoot, "axm.json"), JSON.stringify({ agents: [], ...options.settings }, null, 2));
|
|
76
|
+
// JSON is valid YAML, so the lockfile fixture needs no emitter.
|
|
77
|
+
fs.writeFileSync(nodePath.join(workspaceRoot, "axm-lock.yaml"), JSON.stringify({ lockfileVersion: 7, skills: {}, ...options.lockfile }));
|
|
78
|
+
}
|
|
79
|
+
for (const [relativePath, contents] of Object.entries(options.files ?? {})) {
|
|
80
|
+
writeFile(relativePath, contents);
|
|
81
|
+
}
|
|
82
|
+
for (const [relativePath, contents] of Object.entries(options.homeFiles ?? {})) {
|
|
83
|
+
writeHomeFile(relativePath, contents);
|
|
84
|
+
}
|
|
85
|
+
const interaction = ResolvePlanInteractionTest();
|
|
86
|
+
const environment = ConfigProvider.layer(ConfigProvider.fromEnv({ env: { AXM_USER_HOME: home } }));
|
|
87
|
+
// Configuration flows never fetch a source; a fixture that could would be
|
|
88
|
+
// describing a different use case.
|
|
89
|
+
const sourceProviders = Layer.succeed(SourceHostProviders, {
|
|
90
|
+
find: () => Effect.succeed([]),
|
|
91
|
+
resolveNamedRegistry: () => Effect.die("no named registry in this fixture"),
|
|
92
|
+
fetch: () => Effect.die("no source fetch in this fixture"),
|
|
93
|
+
cloneUrl: () => Option.none(),
|
|
94
|
+
origin: () => "fixture",
|
|
95
|
+
});
|
|
96
|
+
// No configuration flow reaches a network; a fixture that could would be
|
|
97
|
+
// describing a different use case.
|
|
98
|
+
const transport = Layer.succeed(HttpClient.HttpClient, HttpClient.make(() => Effect.die("no HTTP request in this fixture")));
|
|
99
|
+
// Configuration flows plan their own rule projection through the rule
|
|
100
|
+
// manager; the aggregate participant registry is a reconciliation concern
|
|
101
|
+
// these fixtures do not exercise, so it is present but empty.
|
|
102
|
+
const participants = Layer.succeed(ProjectionParticipants, emptyProjectionParticipants);
|
|
103
|
+
const installedExecutables = new Set(options.installedExecutables ?? []);
|
|
104
|
+
const executables = Layer.succeed(AgentExecutableResolver, {
|
|
105
|
+
exists: (name) => Effect.succeed(installedExecutables.has(name)),
|
|
106
|
+
});
|
|
107
|
+
// One environment, built outward: the workspace state and the ports over
|
|
108
|
+
// it, then the projection services that read them, then the rule manager
|
|
109
|
+
// that reads both. `provideMerge` keeps every layer's output in the result,
|
|
110
|
+
// so a service a manager keeps in `R` is still there when it is reached.
|
|
111
|
+
const base = Layer.provideMerge(Layer.mergeAll(WorkspaceLayerLive({
|
|
112
|
+
scope,
|
|
113
|
+
projectRoot: decodeAbsolutePathSync(root),
|
|
114
|
+
allowUninitialized: options.settings === undefined,
|
|
115
|
+
}), CodingAgentRepositoryLive, NativeWriteAuthorityLive, participants, sourceProviders, transport, interaction.layer, executables, PlanInvocationTest), environment);
|
|
116
|
+
const withProjection = Layer.provideMerge(Layer.mergeAll(WorkspaceInvariantFactsLive, WorkspaceCatalogLive), base);
|
|
117
|
+
const services = Layer.provideMerge(RuleManagerLive, withProjection);
|
|
118
|
+
return {
|
|
119
|
+
root,
|
|
120
|
+
home,
|
|
121
|
+
workspaceRoot,
|
|
122
|
+
writeFile,
|
|
123
|
+
writeHomeFile,
|
|
124
|
+
readFile,
|
|
125
|
+
exists,
|
|
126
|
+
/** Every file under the project root. */
|
|
127
|
+
snapshot: () => snapshotUnder(root),
|
|
128
|
+
/** Every file under the pinned user home. */
|
|
129
|
+
homeSnapshot: () => snapshotUnder(home),
|
|
130
|
+
/** What the plan interaction port was asked to present and confirm. */
|
|
131
|
+
interactionState: () => interaction.state,
|
|
132
|
+
provide: (effect) => effect.pipe(Effect.provide(services)),
|
|
133
|
+
cleanup: () => {
|
|
134
|
+
fs.rmSync(root, { recursive: true, force: true });
|
|
135
|
+
fs.rmSync(home, { recursive: true, force: true });
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
};
|
|
139
|
+
/**
|
|
140
|
+
* A bare directory and the services setup needs to turn it into a workspace.
|
|
141
|
+
*
|
|
142
|
+
* Setup builds its own workspace, so this fixture deliberately provides no
|
|
143
|
+
* workspace state: only the platform-adjacent ports it reads — the pinned
|
|
144
|
+
* user home, the coding-agent catalog and executable probe, and a recording
|
|
145
|
+
* initialization-interaction port whose calls are the evidence channel for
|
|
146
|
+
* every claim about what setup asked.
|
|
147
|
+
*/
|
|
148
|
+
export const makeSetupFixture = (options = {}) => {
|
|
149
|
+
const root = fs.realpathSync(fs.mkdtempSync(nodePath.join(os.tmpdir(), "axm-setup-")));
|
|
150
|
+
const home = fs.realpathSync(fs.mkdtempSync(nodePath.join(os.tmpdir(), "axm-setup-home-")));
|
|
151
|
+
const writeUnder = (base) => (relativePath, contents) => {
|
|
152
|
+
const file = nodePath.join(base, relativePath);
|
|
153
|
+
fs.mkdirSync(nodePath.dirname(file), { recursive: true });
|
|
154
|
+
fs.writeFileSync(file, contents);
|
|
155
|
+
};
|
|
156
|
+
const writeFile = writeUnder(root);
|
|
157
|
+
const writeHomeFile = writeUnder(home);
|
|
158
|
+
for (const [relativePath, contents] of Object.entries(options.files ?? {})) {
|
|
159
|
+
writeFile(relativePath, contents);
|
|
160
|
+
}
|
|
161
|
+
for (const [relativePath, contents] of Object.entries(options.homeFiles ?? {})) {
|
|
162
|
+
writeHomeFile(relativePath, contents);
|
|
163
|
+
}
|
|
164
|
+
const snapshotUnder = (base) => {
|
|
165
|
+
const entries = [];
|
|
166
|
+
const walk = (directory) => {
|
|
167
|
+
for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
|
|
168
|
+
const absolute = nodePath.join(directory, entry.name);
|
|
169
|
+
const relative = nodePath.relative(base, absolute);
|
|
170
|
+
if (entry.isSymbolicLink()) {
|
|
171
|
+
entries.push([relative, `symlink:${fs.readlinkSync(absolute)}`]);
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
if (entry.isDirectory()) {
|
|
175
|
+
entries.push([relative, "directory"]);
|
|
176
|
+
walk(absolute);
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
entries.push([relative, fs.readFileSync(absolute, "utf8")]);
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
walk(base);
|
|
183
|
+
return entries.sort((left, right) => left[0].localeCompare(right[0]));
|
|
184
|
+
};
|
|
185
|
+
const interaction = WorkspaceInitializationInteractionTest({
|
|
186
|
+
...(options.selectAgents === undefined
|
|
187
|
+
? {}
|
|
188
|
+
: { selectAgents: () => Effect.succeed(options.selectAgents ?? []) }),
|
|
189
|
+
...(options.confirmSetupPlan === undefined
|
|
190
|
+
? {}
|
|
191
|
+
: { confirmSetupPlan: () => Effect.succeed(options.confirmSetupPlan ?? true) }),
|
|
192
|
+
...(options.confirmInstructionSync === undefined
|
|
193
|
+
? {}
|
|
194
|
+
: { confirmInstructionSync: () => Effect.succeed(options.confirmInstructionSync ?? true) }),
|
|
195
|
+
});
|
|
196
|
+
const installedExecutables = new Set(options.installedExecutables ?? []);
|
|
197
|
+
const services = Layer.mergeAll(ConfigProvider.layer(ConfigProvider.fromEnv({ env: { AXM_USER_HOME: home, HOME: home } })), CodingAgentRepositoryLive, Layer.succeed(AgentExecutableResolver, {
|
|
198
|
+
exists: (name) => Effect.succeed(installedExecutables.has(name)),
|
|
199
|
+
}), interaction.layer);
|
|
200
|
+
return {
|
|
201
|
+
root,
|
|
202
|
+
home,
|
|
203
|
+
writeFile,
|
|
204
|
+
writeHomeFile,
|
|
205
|
+
readFile: (relativePath) => fs.readFileSync(nodePath.join(root, relativePath), "utf8"),
|
|
206
|
+
exists: (relativePath) => fs.existsSync(nodePath.join(root, relativePath)),
|
|
207
|
+
/** Every file under the bare project directory. */
|
|
208
|
+
snapshot: () => snapshotUnder(root),
|
|
209
|
+
/** Every file under the pinned user home. */
|
|
210
|
+
homeSnapshot: () => snapshotUnder(home),
|
|
211
|
+
/** What the initialization interaction port was asked. */
|
|
212
|
+
promptState: () => interaction.state,
|
|
213
|
+
provide: (effect) => effect.pipe(Effect.provide(services)),
|
|
214
|
+
cleanup: () => {
|
|
215
|
+
fs.rmSync(root, { recursive: true, force: true });
|
|
216
|
+
fs.rmSync(home, { recursive: true, force: true });
|
|
217
|
+
},
|
|
218
|
+
};
|
|
219
|
+
};
|
|
9
220
|
//# sourceMappingURL=testing.js.map
|
package/package.json
CHANGED
|
@@ -4,12 +4,14 @@
|
|
|
4
4
|
"url": "https://github.com/agentxm/axm/issues"
|
|
5
5
|
},
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"@agentxm/agent-integration": "^0.28.
|
|
8
|
-
"@agentxm/extension-
|
|
9
|
-
"@agentxm/extension-
|
|
10
|
-
"@agentxm/extension-
|
|
11
|
-
"@agentxm/workspace-operations": "^0.28.
|
|
12
|
-
"@agentxm/workspace-
|
|
7
|
+
"@agentxm/agent-integration": "^0.28.13",
|
|
8
|
+
"@agentxm/extension-materialization": "^0.28.13",
|
|
9
|
+
"@agentxm/extension-model": "^0.28.13",
|
|
10
|
+
"@agentxm/extension-sources": "^0.28.13",
|
|
11
|
+
"@agentxm/workspace-operations": "^0.28.13",
|
|
12
|
+
"@agentxm/workspace-projection": "^0.28.13",
|
|
13
|
+
"@agentxm/workspace-state": "^0.28.13",
|
|
14
|
+
"@agentxm/workspace-transactions": "^0.28.13",
|
|
13
15
|
"effect": "4.0.0-rc.112"
|
|
14
16
|
},
|
|
15
17
|
"description": "AXM workspace-configuration feature: setup, configured-agent membership, instruction management, and inline workspace capabilities for the axm CLI. Unstable and unsupported — use the axm.sh CLI.",
|
|
@@ -50,11 +52,11 @@
|
|
|
50
52
|
"access": "public"
|
|
51
53
|
},
|
|
52
54
|
"repository": {
|
|
53
|
-
"directory": "packages/workspace-configuration",
|
|
55
|
+
"directory": "packages/core/workspace-configuration",
|
|
54
56
|
"type": "git",
|
|
55
57
|
"url": "https://github.com/agentxm/axm.git"
|
|
56
58
|
},
|
|
57
59
|
"sideEffects": false,
|
|
58
60
|
"type": "module",
|
|
59
|
-
"version": "0.28.
|
|
60
|
-
}
|
|
61
|
+
"version": "0.28.13"
|
|
62
|
+
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Instruction-management policy over the kernel's instruction semantics:
|
|
3
|
-
* observation, readiness preflight, reconciliation transitions, and disabling
|
|
4
|
-
* instruction-file management. Failures stay typed through this feature; the
|
|
5
|
-
* application boundary owns their rendering.
|
|
6
|
-
*
|
|
7
|
-
* @experimental This API is unstable and may change without notice.
|
|
8
|
-
*/
|
|
9
|
-
import * as Effect from "effect/Effect";
|
|
10
|
-
import * as Option from "effect/Option";
|
|
11
|
-
import type { WorkspaceMutationsService } from "@agentxm/workspace-state";
|
|
12
|
-
import { assertInstructionTargetsSafe, assertInstructionsGitignoreSafe } from "@agentxm/extension-workspace";
|
|
13
|
-
import type { InstructionProjectionSnapshot, ResolvedInstructionsConfig } from "@agentxm/extension-workspace";
|
|
14
|
-
import { WorkspaceConfigurationFailed } from "./errors.js";
|
|
15
|
-
/** The one observation a command's planning derives its views from. */
|
|
16
|
-
export declare const observeInstructions: (args: {
|
|
17
|
-
readonly ws: WorkspaceMutationsService;
|
|
18
|
-
readonly config: ResolvedInstructionsConfig;
|
|
19
|
-
}) => Effect.Effect<InstructionProjectionSnapshot, import("@agentxm/workspace-state").WorkspaceSettingsReadFailure, import("effect/FileSystem").FileSystem | import("effect/Path").Path>;
|
|
20
|
-
export declare const activeInstructionsConfig: (ws: WorkspaceMutationsService) => Effect.Effect<Option.Option<ResolvedInstructionsConfig>, import("@agentxm/workspace-state").WorkspaceSettingsReadFailure, never>;
|
|
21
|
-
export declare const instructionStateIsCurrent: (snapshot: InstructionProjectionSnapshot) => boolean;
|
|
22
|
-
/** The typed failure a readiness preflight can surface. */
|
|
23
|
-
export type InstructionReadinessFailure = Effect.Error<ReturnType<typeof assertInstructionTargetsSafe>> | Effect.Error<ReturnType<typeof assertInstructionsGitignoreSafe>>;
|
|
24
|
-
export declare const instructionReconciliationReadiness: (args: {
|
|
25
|
-
readonly ws: WorkspaceMutationsService;
|
|
26
|
-
readonly snapshot: InstructionProjectionSnapshot;
|
|
27
|
-
}) => Effect.Effect<Option.None<InstructionReadinessFailure> | Option.Some<InstructionReadinessFailure>, never, import("effect/FileSystem").FileSystem | import("effect/Path").Path>;
|
|
28
|
-
/**
|
|
29
|
-
* Remove every alias the given configuration owns, observing fresh so the
|
|
30
|
-
* decision reflects the workspace at the moment of removal. Used before a new
|
|
31
|
-
* configuration is reconciled, so a changed source filename or alias policy
|
|
32
|
-
* never leaves the old arrangement behind. Refuses on an unowned target like
|
|
33
|
-
* every other path.
|
|
34
|
-
*/
|
|
35
|
-
export declare const removeInstructionTargetsFor: (args: {
|
|
36
|
-
readonly ws: WorkspaceMutationsService;
|
|
37
|
-
readonly config: ResolvedInstructionsConfig;
|
|
38
|
-
}) => Effect.Effect<string[], import("@agentxm/workspace-state").WorkspaceSnapshotError | import("@agentxm/extension-workspace").InstructionMaintenanceFailed | import("@agentxm/workspace-state").WorkspaceSettingsReadFailure, import("effect/FileSystem").FileSystem | import("effect/Path").Path>;
|
|
39
|
-
/**
|
|
40
|
-
* Runs inside the workspace transaction: preflight against a fresh
|
|
41
|
-
* observation (the plan's readiness check ran before the transaction opened),
|
|
42
|
-
* apply the transition, reconcile, and verify from the sync's own readback.
|
|
43
|
-
*/
|
|
44
|
-
export declare const reconcileInstructionTransition: <A, E>(args: {
|
|
45
|
-
readonly ws: WorkspaceMutationsService;
|
|
46
|
-
readonly config: ResolvedInstructionsConfig;
|
|
47
|
-
readonly preflightConfig?: ResolvedInstructionsConfig;
|
|
48
|
-
readonly transition: Effect.Effect<A, E>;
|
|
49
|
-
}) => Effect.Effect<A, WorkspaceConfigurationFailed | import("@agentxm/extension-workspace").InstructionMaintenanceFailure | import("@agentxm/workspace-state").WorkspaceSettingsReadFailure | E, import("effect/FileSystem").FileSystem | import("effect/Path").Path>;
|
|
50
|
-
export declare const disableInstructionManagement: (args: {
|
|
51
|
-
readonly ws: WorkspaceMutationsService;
|
|
52
|
-
readonly config: ResolvedInstructionsConfig;
|
|
53
|
-
}) => Effect.Effect<{
|
|
54
|
-
removed: string[];
|
|
55
|
-
gitignore: string | undefined;
|
|
56
|
-
}, import("@agentxm/workspace-state").WorkspaceSnapshotError | import("@agentxm/workspace-state").SettingsWriteError | import("@agentxm/extension-workspace").InstructionMaintenanceFailed | import("@agentxm/workspace-state").PathTraversalDetected | import("@agentxm/workspace-state").SymlinkCreationError | import("@agentxm/workspace-state").WorkspaceRootEscape | import("@agentxm/workspace-state").SettingsIoError | import("@agentxm/workspace-state").SettingsParseError | import("@agentxm/workspace-state").SettingsDecodeError, import("effect/FileSystem").FileSystem | import("effect/Path").Path>;
|
|
57
|
-
//# sourceMappingURL=instruction-reconciliation.d.ts.map
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Instruction-management policy over the kernel's instruction semantics:
|
|
3
|
-
* observation, readiness preflight, reconciliation transitions, and disabling
|
|
4
|
-
* instruction-file management. Failures stay typed through this feature; the
|
|
5
|
-
* application boundary owns their rendering.
|
|
6
|
-
*
|
|
7
|
-
* @experimental This API is unstable and may change without notice.
|
|
8
|
-
*/
|
|
9
|
-
import * as Effect from "effect/Effect";
|
|
10
|
-
import * as Option from "effect/Option";
|
|
11
|
-
import { assertInstructionTargetsSafe, assertInstructionsGitignoreSafe, instructionProjectionIsCurrent, observeInstructionProjection, removeManagedInstructionTargets, removeInstructionsGitignore, resolveInstructionsConfig, syncInstructions, } from "@agentxm/extension-workspace";
|
|
12
|
-
import { WorkspaceConfigurationFailed } from "./errors.js";
|
|
13
|
-
const configuredAgents = (ws) => ws.getConfiguredAgents();
|
|
14
|
-
/** The one observation a command's planning derives its views from. */
|
|
15
|
-
export const observeInstructions = Effect.fn("Instructions.observe")(function* (args) {
|
|
16
|
-
const agents = yield* configuredAgents(args.ws);
|
|
17
|
-
return yield* observeInstructionProjection({
|
|
18
|
-
workspaceRoot: args.ws.baseDir,
|
|
19
|
-
scope: args.ws.scope,
|
|
20
|
-
configuredAgents: agents,
|
|
21
|
-
config: args.config,
|
|
22
|
-
});
|
|
23
|
-
});
|
|
24
|
-
export const activeInstructionsConfig = Effect.fn("Instructions.activeConfig")(function* (ws) {
|
|
25
|
-
const value = yield* ws.getInstructionsConfig();
|
|
26
|
-
if (Option.isNone(value) || value.value === false) {
|
|
27
|
-
return Option.none();
|
|
28
|
-
}
|
|
29
|
-
return Option.some(resolveInstructionsConfig(value.value));
|
|
30
|
-
});
|
|
31
|
-
export const instructionStateIsCurrent = (snapshot) => snapshot.status.missingSources.length === 0 && instructionProjectionIsCurrent(snapshot);
|
|
32
|
-
export const instructionReconciliationReadiness = Effect.fn("Instructions.reconciliationReadiness")(function* (args) {
|
|
33
|
-
return yield* Effect.result(Effect.all([
|
|
34
|
-
assertInstructionTargetsSafe(args.snapshot.status),
|
|
35
|
-
assertInstructionsGitignoreSafe(args.ws.baseDir),
|
|
36
|
-
], { concurrency: 1, discard: true })).pipe(Effect.map((result) => result._tag === "Success"
|
|
37
|
-
? Option.none()
|
|
38
|
-
: Option.some(result.failure)));
|
|
39
|
-
});
|
|
40
|
-
/**
|
|
41
|
-
* Remove every alias the given configuration owns, observing fresh so the
|
|
42
|
-
* decision reflects the workspace at the moment of removal. Used before a new
|
|
43
|
-
* configuration is reconciled, so a changed source filename or alias policy
|
|
44
|
-
* never leaves the old arrangement behind. Refuses on an unowned target like
|
|
45
|
-
* every other path.
|
|
46
|
-
*/
|
|
47
|
-
export const removeInstructionTargetsFor = (args) => Effect.gen(function* () {
|
|
48
|
-
const snapshot = yield* observeInstructions(args);
|
|
49
|
-
return yield* removeManagedInstructionTargets({ snapshot, dryRun: false });
|
|
50
|
-
});
|
|
51
|
-
/**
|
|
52
|
-
* Runs inside the workspace transaction: preflight against a fresh
|
|
53
|
-
* observation (the plan's readiness check ran before the transaction opened),
|
|
54
|
-
* apply the transition, reconcile, and verify from the sync's own readback.
|
|
55
|
-
*/
|
|
56
|
-
export const reconcileInstructionTransition = (args) => Effect.gen(function* () {
|
|
57
|
-
const agents = yield* configuredAgents(args.ws);
|
|
58
|
-
const preflight = yield* observeInstructions({
|
|
59
|
-
ws: args.ws,
|
|
60
|
-
config: args.preflightConfig ?? args.config,
|
|
61
|
-
});
|
|
62
|
-
yield* assertInstructionTargetsSafe(preflight.status);
|
|
63
|
-
yield* assertInstructionsGitignoreSafe(args.ws.baseDir);
|
|
64
|
-
const transitionResult = yield* args.transition;
|
|
65
|
-
const syncResult = yield* syncInstructions({
|
|
66
|
-
workspaceRoot: args.ws.baseDir,
|
|
67
|
-
scope: args.ws.scope,
|
|
68
|
-
configuredAgents: agents,
|
|
69
|
-
config: args.config,
|
|
70
|
-
dryRun: false,
|
|
71
|
-
});
|
|
72
|
-
if (!instructionProjectionIsCurrent(syncResult.snapshot)) {
|
|
73
|
-
return yield* new WorkspaceConfigurationFailed({
|
|
74
|
-
category: "internal",
|
|
75
|
-
detail: "Instruction reconciliation did not reach the desired state",
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
return transitionResult;
|
|
79
|
-
}).pipe(Effect.withSpan("Instructions.reconcileTransition"));
|
|
80
|
-
export const disableInstructionManagement = Effect.fn("Instructions.disableManagement")(function* (args) {
|
|
81
|
-
yield* assertInstructionsGitignoreSafe(args.ws.baseDir);
|
|
82
|
-
const removed = yield* removeInstructionTargetsFor(args);
|
|
83
|
-
const gitignore = yield* removeInstructionsGitignore({
|
|
84
|
-
workspaceRoot: args.ws.baseDir,
|
|
85
|
-
dryRun: false,
|
|
86
|
-
});
|
|
87
|
-
yield* args.ws.setInstructionsConfig(false);
|
|
88
|
-
return {
|
|
89
|
-
removed,
|
|
90
|
-
gitignore: Option.getOrUndefined(gitignore),
|
|
91
|
-
};
|
|
92
|
-
});
|
|
93
|
-
//# sourceMappingURL=instruction-reconciliation.js.map
|
package/dist/src/mcp-import.d.ts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Inline MCP adoption policy: discover import sources from configured agents'
|
|
3
|
-
* native MCP configs, rewrite adopted entries with AXM management metadata,
|
|
4
|
-
* remove entries converted into managed packages, and apply an inline import
|
|
5
|
-
* as one validated workspace transaction. Prompting, planning, and rendering
|
|
6
|
-
* stay with the application.
|
|
7
|
-
*
|
|
8
|
-
* @experimental This API is unstable and may change without notice.
|
|
9
|
-
*/
|
|
10
|
-
import * as Effect from "effect/Effect";
|
|
11
|
-
import * as FileSystem from "effect/FileSystem";
|
|
12
|
-
import * as Path from "effect/Path";
|
|
13
|
-
import { type WorkspaceMutationsService } from "@agentxm/workspace-state";
|
|
14
|
-
import { WorkspaceConfigurationFailed } from "./errors.js";
|
|
15
|
-
import type { McpImportAdoption, McpImportCandidate, McpImportSource } from "./mcp-import-preflight.js";
|
|
16
|
-
/**
|
|
17
|
-
* Discover the native MCP config sources the configured agents contribute for
|
|
18
|
-
* this workspace scope, with unsupported-format findings.
|
|
19
|
-
*/
|
|
20
|
-
export declare const collectMcpImportSources: (ws: WorkspaceMutationsService, fs: FileSystem.FileSystem, path: Path.Path) => Effect.Effect<{
|
|
21
|
-
sources: McpImportSource[];
|
|
22
|
-
skipped: {
|
|
23
|
-
readonly name: string;
|
|
24
|
-
readonly reason: string;
|
|
25
|
-
}[];
|
|
26
|
-
}, WorkspaceConfigurationFailed | import("@agentxm/workspace-state").WorkspaceSettingsReadFailure, never>;
|
|
27
|
-
/**
|
|
28
|
-
* Remove a native entry converted into a managed package, refusing when the
|
|
29
|
-
* native config changed since the conversion was planned.
|
|
30
|
-
*/
|
|
31
|
-
export declare const removeConvertedMcpConfig: (fs: FileSystem.FileSystem, adoption: McpImportAdoption) => Effect.Effect<void, WorkspaceConfigurationFailed>;
|
|
32
|
-
/**
|
|
33
|
-
* Adopt the losslessly importable candidates as inline settings entries and
|
|
34
|
-
* mark their native entries as AXM-managed, in one validated workspace
|
|
35
|
-
* transaction.
|
|
36
|
-
*/
|
|
37
|
-
export declare const applyMcpImport: <HookError = never>(candidates: ReadonlyArray<McpImportCandidate>, ws: WorkspaceMutationsService, fs: FileSystem.FileSystem, hooks?: {
|
|
38
|
-
readonly beforeAdoptionWrite?: (adoption: McpImportAdoption) => Effect.Effect<void, HookError>;
|
|
39
|
-
}) => Effect.Effect<void, WorkspaceConfigurationFailed | import("@agentxm/workspace-state").WorkspaceSnapshotError | import("@agentxm/workspace-state").SettingsWriteError | import("@agentxm/workspace-state").WorkspaceRootEscape | import("@agentxm/workspace-state").SettingsIoError | import("@agentxm/workspace-state").SettingsParseError | import("@agentxm/workspace-state").SettingsDecodeError | import("@agentxm/workspace-state").WorkspaceDirectoryError | import("@agentxm/workspace-state").TransitionLockError | import("@agentxm/workspace-state").TransitionLockUnavailable | import("@agentxm/workspace-state").WorkspaceTransitionCompromised | import("@agentxm/workspace-state").WorkspaceRestorationIncomplete | HookError, never>;
|
|
40
|
-
//# sourceMappingURL=mcp-import.d.ts.map
|
package/dist/src/membership.d.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Configured-agent membership policy: agent-id validation for membership
|
|
3
|
-
* changes and the atomic application of membership and materialization steps
|
|
4
|
-
* through one workspace transaction. The application supplies the failure
|
|
5
|
-
* conversion so step categories and details stay byte-identical with its
|
|
6
|
-
* rendered errors.
|
|
7
|
-
*
|
|
8
|
-
* @experimental This API is unstable and may change without notice.
|
|
9
|
-
*/
|
|
10
|
-
import * as Effect from "effect/Effect";
|
|
11
|
-
import { StepFailure, type JobStepResult, type PlannedJobStep } from "@agentxm/workspace-operations";
|
|
12
|
-
import type { WorkspaceMutationsService } from "@agentxm/workspace-state";
|
|
13
|
-
import { WorkspaceConfigurationFailed } from "./errors.js";
|
|
14
|
-
export declare const dedupe: (values: ReadonlyArray<string>) => ReadonlyArray<string>;
|
|
15
|
-
export declare const validateAgentIds: (ids: ReadonlyArray<string>) => Effect.Effect<ReadonlyArray<string>, WorkspaceConfigurationFailed>;
|
|
16
|
-
interface AtomicMembershipStepsArgs<Requirements, Output, ValidateError> {
|
|
17
|
-
readonly ws: WorkspaceMutationsService;
|
|
18
|
-
readonly steps: ReadonlyArray<PlannedJobStep<Requirements, Output>>;
|
|
19
|
-
readonly validate: (results: ReadonlyArray<JobStepResult<Output>>) => Effect.Effect<void, ValidateError, Requirements>;
|
|
20
|
-
/** Application-owned conversion into the plan-step failure vocabulary. */
|
|
21
|
-
readonly toStepFailure: (failure: unknown) => StepFailure;
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Keep plan-level preview and per-step results while applying every membership
|
|
25
|
-
* and artifact step through one workspace transaction.
|
|
26
|
-
*/
|
|
27
|
-
export declare const makeAtomicMembershipSteps: <Requirements, Output, ValidateError>(args: AtomicMembershipStepsArgs<Requirements, Output, ValidateError>) => Effect.Effect<readonly PlannedJobStep<Requirements, Output>[], never, never>;
|
|
28
|
-
export {};
|
|
29
|
-
//# sourceMappingURL=membership.d.ts.map
|
package/dist/src/membership.js
DELETED
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Configured-agent membership policy: agent-id validation for membership
|
|
3
|
-
* changes and the atomic application of membership and materialization steps
|
|
4
|
-
* through one workspace transaction. The application supplies the failure
|
|
5
|
-
* conversion so step categories and details stay byte-identical with its
|
|
6
|
-
* rendered errors.
|
|
7
|
-
*
|
|
8
|
-
* @experimental This API is unstable and may change without notice.
|
|
9
|
-
*/
|
|
10
|
-
import * as Effect from "effect/Effect";
|
|
11
|
-
import * as Ref from "effect/Ref";
|
|
12
|
-
import { HOSTED_AGENTS_BY_ID, HOSTED_AGENT_IDS, } from "@agentxm/extension-model/unstable/agent-capabilities";
|
|
13
|
-
import { CONFIGURABLE_AGENT_IDS } from "@agentxm/extension-model/unstable/agents/types";
|
|
14
|
-
import { StepFailure, } from "@agentxm/workspace-operations";
|
|
15
|
-
import { WorkspaceConfigurationFailed } from "./errors.js";
|
|
16
|
-
const configurableAgentIds = new Set(CONFIGURABLE_AGENT_IDS);
|
|
17
|
-
const hostedAgentIds = new Set(HOSTED_AGENT_IDS);
|
|
18
|
-
const isHostedAgentId = (id) => hostedAgentIds.has(id);
|
|
19
|
-
const numberAt = (values, index) => values[index] ?? 0;
|
|
20
|
-
const editDistance = (left, right) => {
|
|
21
|
-
const previous = Array.from({ length: right.length + 1 }, (_value, index) => index);
|
|
22
|
-
for (let leftIndex = 0; leftIndex < left.length; leftIndex += 1) {
|
|
23
|
-
const current = [leftIndex + 1];
|
|
24
|
-
for (let rightIndex = 0; rightIndex < right.length; rightIndex += 1) {
|
|
25
|
-
const substitutionCost = left[leftIndex] === right[rightIndex] ? 0 : 1;
|
|
26
|
-
current[rightIndex + 1] = Math.min(numberAt(current, rightIndex) + 1, numberAt(previous, rightIndex + 1) + 1, numberAt(previous, rightIndex) + substitutionCost);
|
|
27
|
-
}
|
|
28
|
-
previous.splice(0, previous.length, ...current);
|
|
29
|
-
}
|
|
30
|
-
return previous[right.length] ?? left.length;
|
|
31
|
-
};
|
|
32
|
-
const nearestAgentId = (input) => {
|
|
33
|
-
let best;
|
|
34
|
-
for (const id of CONFIGURABLE_AGENT_IDS) {
|
|
35
|
-
const distance = editDistance(input, id);
|
|
36
|
-
if (best === undefined || distance < best.distance) {
|
|
37
|
-
best = { id, distance };
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
if (best === undefined)
|
|
41
|
-
return undefined;
|
|
42
|
-
return best.distance <= Math.max(3, Math.floor(input.length / 2)) ? best.id : undefined;
|
|
43
|
-
};
|
|
44
|
-
export const dedupe = (values) => Array.from(new Set(values));
|
|
45
|
-
export const validateAgentIds = (ids) => Effect.gen(function* () {
|
|
46
|
-
for (const id of ids) {
|
|
47
|
-
if (id === "universal") {
|
|
48
|
-
return yield* new WorkspaceConfigurationFailed({
|
|
49
|
-
category: "validation",
|
|
50
|
-
detail: "`universal` is always materialized automatically and cannot be added or removed.",
|
|
51
|
-
suggestions: [{ description: "Choose one of the configurable coding-agent IDs." }],
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
if (isHostedAgentId(id)) {
|
|
55
|
-
const agent = HOSTED_AGENTS_BY_ID[id];
|
|
56
|
-
return yield* new WorkspaceConfigurationFailed({
|
|
57
|
-
category: "validation",
|
|
58
|
-
detail: `${agent.name} is a hosted agent and cannot be added to local workspace configuration. ${agent.installTarget.instructions}`,
|
|
59
|
-
suggestions: [
|
|
60
|
-
{
|
|
61
|
-
description: `Open the ${agent.name} skill installation guide.`,
|
|
62
|
-
url: agent.installTarget.docs,
|
|
63
|
-
},
|
|
64
|
-
],
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
if (!configurableAgentIds.has(id)) {
|
|
68
|
-
const nearest = nearestAgentId(id);
|
|
69
|
-
return yield* new WorkspaceConfigurationFailed({
|
|
70
|
-
category: "validation",
|
|
71
|
-
detail: `Unknown agent ID: ${id}`,
|
|
72
|
-
suggestions: [
|
|
73
|
-
nearest === undefined
|
|
74
|
-
? { description: "Inspect supported agent IDs.", cmd: "axm agents list --available" }
|
|
75
|
-
: {
|
|
76
|
-
description: `Did you mean "${nearest}"?`,
|
|
77
|
-
cmd: `axm agents add ${nearest}`,
|
|
78
|
-
},
|
|
79
|
-
],
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
return dedupe(ids);
|
|
84
|
-
});
|
|
85
|
-
const failedResult = (error, message = error.detail) => ({
|
|
86
|
-
result: "error",
|
|
87
|
-
message,
|
|
88
|
-
error,
|
|
89
|
-
});
|
|
90
|
-
const blockedResult = (message) => failedResult(new StepFailure({
|
|
91
|
-
category: "conflict",
|
|
92
|
-
detail: message,
|
|
93
|
-
}), message);
|
|
94
|
-
const rollbackResults = (executable, attempt, transactionError) => {
|
|
95
|
-
const actualFailureIndex = attempt.failedIndex ?? Math.max(0, attempt.results.length - 1);
|
|
96
|
-
const failedLabel = executable[actualFailureIndex]?.label ?? "atomic agent membership validation";
|
|
97
|
-
return executable.map((_, index) => {
|
|
98
|
-
if (index < actualFailureIndex) {
|
|
99
|
-
return blockedResult(`blocked: rolled back after ${failedLabel} failed`);
|
|
100
|
-
}
|
|
101
|
-
if (index > actualFailureIndex) {
|
|
102
|
-
return blockedResult(`blocked by ${failedLabel} failure`);
|
|
103
|
-
}
|
|
104
|
-
const attempted = attempt.results[index];
|
|
105
|
-
return attempted?.result === "error"
|
|
106
|
-
? attempted
|
|
107
|
-
: failedResult(transactionError, transactionError.detail);
|
|
108
|
-
});
|
|
109
|
-
};
|
|
110
|
-
/**
|
|
111
|
-
* Keep plan-level preview and per-step results while applying every membership
|
|
112
|
-
* and artifact step through one workspace transaction.
|
|
113
|
-
*/
|
|
114
|
-
export const makeAtomicMembershipSteps = Effect.fn("Agents.makeAtomicMembershipSteps")(function* (args) {
|
|
115
|
-
if (args.steps.some((step) => step.readiness === "error"))
|
|
116
|
-
return args.steps;
|
|
117
|
-
const executable = args.steps.filter((step) => step.readiness !== "error");
|
|
118
|
-
const attemptRef = yield* Ref.make({ results: [] });
|
|
119
|
-
const transition = args.ws
|
|
120
|
-
.runTransaction({
|
|
121
|
-
transition: Effect.gen(function* () {
|
|
122
|
-
const results = [];
|
|
123
|
-
for (const [index, step] of executable.entries()) {
|
|
124
|
-
const result = yield* step.run.pipe(Effect.catch((error) => Effect.succeed(failedResult(error))));
|
|
125
|
-
results.push(result);
|
|
126
|
-
yield* Ref.set(attemptRef, {
|
|
127
|
-
results: [...results],
|
|
128
|
-
...(result.result === "error" ? { failedIndex: index } : {}),
|
|
129
|
-
});
|
|
130
|
-
if (result.result === "error") {
|
|
131
|
-
return yield* result.error;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
return results;
|
|
135
|
-
}),
|
|
136
|
-
validate: (results) => args.validate(results).pipe(Effect.mapError(args.toStepFailure)),
|
|
137
|
-
})
|
|
138
|
-
.pipe(Effect.catch((transactionError) => Ref.get(attemptRef).pipe(Effect.map((attempt) => rollbackResults(executable, attempt, transactionError._tag === "StepFailure"
|
|
139
|
-
? transactionError
|
|
140
|
-
: args.toStepFailure(transactionError))))));
|
|
141
|
-
const sharedTransition = yield* Effect.cached(transition);
|
|
142
|
-
let resultIndex = 0;
|
|
143
|
-
return args.steps.map((step) => {
|
|
144
|
-
if (step.readiness === "error")
|
|
145
|
-
return step;
|
|
146
|
-
const index = resultIndex;
|
|
147
|
-
resultIndex += 1;
|
|
148
|
-
return {
|
|
149
|
-
...step,
|
|
150
|
-
run: sharedTransition.pipe(Effect.flatMap((results) => {
|
|
151
|
-
const result = results[index];
|
|
152
|
-
return result === undefined
|
|
153
|
-
? new StepFailure({
|
|
154
|
-
category: "internal",
|
|
155
|
-
detail: `Atomic agent membership transition omitted step ${index + 1}`,
|
|
156
|
-
})
|
|
157
|
-
: Effect.succeed(result);
|
|
158
|
-
})),
|
|
159
|
-
};
|
|
160
|
-
});
|
|
161
|
-
});
|
|
162
|
-
//# sourceMappingURL=membership.js.map
|
|
File without changes
|