@agentxm/extension-authoring 0.28.4-bootstrap.0

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.
@@ -0,0 +1,37 @@
1
+ /**
2
+ * New pack operation — scaffolds a new pack directory with manifest.
3
+ *
4
+ * @experimental This API is unstable and may change without notice.
5
+ */
6
+ import * as FileSystem from "effect/FileSystem";
7
+ import * as Path from "effect/Path";
8
+ import { AuthoringFailureAdapter } from "../failure-adapter.js";
9
+ import type { Handle } from "@agentxm/extension-model/unstable/extensions/handle";
10
+ import type { OperationHandler } from "@agentxm/workspace-operations";
11
+ import type { Operation } from "@agentxm/workspace-operations";
12
+ import { WorkspaceMutations } from "@agentxm/workspace-state";
13
+ /**
14
+ * Args for the new pack operation.
15
+ */
16
+ export interface NewPackOperationArgs {
17
+ /** Pack name (without owner). */
18
+ readonly name: string;
19
+ /** Profile (e.g., "@myorg"). */
20
+ readonly owner: Handle;
21
+ }
22
+ /**
23
+ * Scaffold a new pack in the workspace.
24
+ *
25
+ * @experimental This API is unstable and may change without notice.
26
+ */
27
+ export type NewPackOperation = Operation<"new-pack", NewPackOperationArgs>;
28
+ /**
29
+ * New pack operation handler.
30
+ *
31
+ * 1. Compute pack directory path
32
+ * 2. Check if pack manifest already exists
33
+ * 3. Create pack directory
34
+ * 4. Write pack.json manifest
35
+ */
36
+ export declare const newPack: OperationHandler<NewPackOperation, FileSystem.FileSystem | Path.Path | WorkspaceMutations | AuthoringFailureAdapter>;
37
+ //# sourceMappingURL=new-pack.d.ts.map
@@ -0,0 +1,90 @@
1
+ /**
2
+ * New pack operation — scaffolds a new pack directory with manifest.
3
+ *
4
+ * @experimental This API is unstable and may change without notice.
5
+ */
6
+ import * as FileSystem from "effect/FileSystem";
7
+ import * as Path from "effect/Path";
8
+ import * as Effect from "effect/Effect";
9
+ import { AuthoringFailed } from "../errors.js";
10
+ import { AuthoringFailureAdapter, withAdaptedStepFailures } from "../failure-adapter.js";
11
+ import { createCanonicalDirectory, recoverCanonicalDirectory } from "@agentxm/extension-workspace";
12
+ import { preflightCreateOnly } from "../create-preflight.js";
13
+ import { decodeExtensionNameSync, formatFqn } from "@agentxm/extension-model/unstable/extensions";
14
+ import { PACK_MANIFEST_FILENAME, PACK_MANIFEST_SCHEMA_URL, } from "@agentxm/extension-model/unstable/packs/manifest-schema";
15
+ import { WorkspaceMutations } from "@agentxm/workspace-state";
16
+ import { decodeVersionSync } from "@agentxm/extension-model/unstable/version-constraints";
17
+ // -----------------------------------------------------------------------------
18
+ // Public API
19
+ // -----------------------------------------------------------------------------
20
+ /**
21
+ * New pack operation handler.
22
+ *
23
+ * 1. Compute pack directory path
24
+ * 2. Check if pack manifest already exists
25
+ * 3. Create pack directory
26
+ * 4. Write pack.json manifest
27
+ */
28
+ export const newPack = (op) => Effect.gen(function* () {
29
+ const fs = yield* FileSystem.FileSystem;
30
+ const path = yield* Path.Path;
31
+ const ws = yield* WorkspaceMutations;
32
+ const base = ws.baseDir;
33
+ if (ws.layout.scope !== "project") {
34
+ return yield* new AuthoringFailed({
35
+ category: "validation",
36
+ detail: "New packs can only be scaffolded in a project workspace",
37
+ });
38
+ }
39
+ const initialVersion = decodeVersionSync("0.0.1");
40
+ const { name, owner } = op.args;
41
+ const extensionName = decodeExtensionNameSync(name);
42
+ const fqn = formatFqn({ owner, type: "pack", name: extensionName });
43
+ // 1. Compute pack directory path
44
+ const canonicalPath = path.join(ws.layout.authoredRoot("pack"), name);
45
+ const configuredPacks = yield* ws.getConfiguredPackEntries();
46
+ yield* recoverCanonicalDirectory({
47
+ baseDir: base,
48
+ canonicalPath,
49
+ });
50
+ yield* preflightCreateOnly({
51
+ subject: "Pack",
52
+ name,
53
+ configured: Object.hasOwn(configuredPacks, name),
54
+ destinations: [canonicalPath],
55
+ });
56
+ const manifest = {
57
+ $schema: PACK_MANIFEST_SCHEMA_URL,
58
+ owner,
59
+ type: "pack",
60
+ name: extensionName,
61
+ version: initialVersion,
62
+ dependencies: {},
63
+ };
64
+ yield* createCanonicalDirectory({
65
+ baseDir: base,
66
+ canonicalPath,
67
+ subject: "Pack",
68
+ requiredFiles: [PACK_MANIFEST_FILENAME],
69
+ populate: (stagingPath) => {
70
+ const manifestPath = path.join(stagingPath, PACK_MANIFEST_FILENAME);
71
+ return Effect.gen(function* () {
72
+ yield* fs.makeDirectory(stagingPath, { recursive: true }).pipe(Effect.mapError((e) => new AuthoringFailed({
73
+ category: "internal",
74
+ detail: `Failed to create pack directory: ${stagingPath}`,
75
+ cause: e,
76
+ })));
77
+ yield* fs.writeFileString(manifestPath, JSON.stringify(manifest, null, 2) + "\n").pipe(Effect.mapError((e) => new AuthoringFailed({
78
+ category: "internal",
79
+ detail: `Failed to write pack manifest: ${manifestPath}`,
80
+ cause: e,
81
+ })));
82
+ });
83
+ },
84
+ });
85
+ return {
86
+ result: "success",
87
+ message: `Created pack ${fqn}`,
88
+ };
89
+ }).pipe(withAdaptedStepFailures);
90
+ //# sourceMappingURL=new-pack.js.map
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Remove-from-pack operation — applies a precomputed manifest-remove delta to a pack manifest.
3
+ *
4
+ * Validates manifest precondition (stale check) before writing.
5
+ *
6
+ * @experimental This API is unstable and may change without notice.
7
+ */
8
+ import * as FileSystem from "effect/FileSystem";
9
+ import * as Path from "effect/Path";
10
+ import { AuthoringFailureAdapter } from "../failure-adapter.js";
11
+ import type { Handle } from "@agentxm/extension-model/unstable/extensions";
12
+ import type { OperationHandler } from "@agentxm/workspace-operations";
13
+ import type { Operation } from "@agentxm/workspace-operations";
14
+ import { WorkspaceMutations } from "@agentxm/workspace-state";
15
+ /**
16
+ * Args for the remove-from-pack operation.
17
+ */
18
+ export interface RemoveFromPackOperationArgs {
19
+ /** Pack name (without owner). */
20
+ readonly packName: string;
21
+ /** Pack owner (e.g., "@myorg"). */
22
+ readonly packOwner: Handle;
23
+ /** Precomputed manifest delta: extension names to remove. */
24
+ readonly removals: ReadonlyArray<string>;
25
+ /** Manifest content hash at plan time for stale-check. */
26
+ readonly manifestHash: string;
27
+ }
28
+ /**
29
+ * Remove extensions from a pack manifest.
30
+ *
31
+ * @experimental This API is unstable and may change without notice.
32
+ */
33
+ export type RemoveFromPackOperation = Operation<"remove-from-pack", RemoveFromPackOperationArgs>;
34
+ /**
35
+ * Remove-from-pack operation handler.
36
+ *
37
+ * 1. Short-circuit if removals list is empty (no-op)
38
+ * 2. Read current manifest and compute hash
39
+ * 3. Compare hash with args.manifestHash (stale check)
40
+ * 4. Apply removals to manifest
41
+ * 5. Write updated manifest
42
+ */
43
+ export declare const removeFromPack: OperationHandler<RemoveFromPackOperation, FileSystem.FileSystem | Path.Path | WorkspaceMutations | AuthoringFailureAdapter>;
44
+ //# sourceMappingURL=remove-from-pack.d.ts.map
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Remove-from-pack operation — applies a precomputed manifest-remove delta to a pack manifest.
3
+ *
4
+ * Validates manifest precondition (stale check) before writing.
5
+ *
6
+ * @experimental This API is unstable and may change without notice.
7
+ */
8
+ import * as FileSystem from "effect/FileSystem";
9
+ import * as Path from "effect/Path";
10
+ import * as Effect from "effect/Effect";
11
+ import * as Schema from "effect/Schema";
12
+ import { AuthoringFailed } from "../errors.js";
13
+ import { AuthoringFailureAdapter, withAdaptedStepFailures } from "../failure-adapter.js";
14
+ import { WorkspaceMutations } from "@agentxm/workspace-state";
15
+ import { isWorkspaceSourceLocator } from "@agentxm/extension-model/unstable/sources/workspace";
16
+ import { PACK_MANIFEST_FILENAME, PackManifestSchema, } from "@agentxm/extension-model/unstable/packs/manifest-schema";
17
+ import { packManifestArtifact } from "./artifact.js";
18
+ import { hashContent } from "./hash-content.js";
19
+ // -----------------------------------------------------------------------------
20
+ // Public API
21
+ // -----------------------------------------------------------------------------
22
+ /**
23
+ * Remove-from-pack operation handler.
24
+ *
25
+ * 1. Short-circuit if removals list is empty (no-op)
26
+ * 2. Read current manifest and compute hash
27
+ * 3. Compare hash with args.manifestHash (stale check)
28
+ * 4. Apply removals to manifest
29
+ * 5. Write updated manifest
30
+ */
31
+ export const removeFromPack = (op) => Effect.gen(function* () {
32
+ const fs = yield* FileSystem.FileSystem;
33
+ const path = yield* Path.Path;
34
+ const ws = yield* WorkspaceMutations;
35
+ if (ws.layout.scope !== "project") {
36
+ return yield* new AuthoringFailed({
37
+ category: "validation",
38
+ detail: "Authored packs can only be edited in a project workspace",
39
+ });
40
+ }
41
+ const { packName, packOwner, removals, manifestHash } = op.args;
42
+ const configured = (yield* ws.getConfiguredPackEntries())[packName];
43
+ if (configured === undefined || !isWorkspaceSourceLocator(configured.source)) {
44
+ return yield* new AuthoringFailed({
45
+ category: "conflict",
46
+ detail: `Pack "${packName}" is not an authored workspace pack`,
47
+ recover: "Only workspace-authored packs can be edited in place.",
48
+ });
49
+ }
50
+ // 1. Short-circuit if nothing to remove
51
+ if (removals.length === 0) {
52
+ return { result: "success", message: "No pack entries removed" };
53
+ }
54
+ // 2. Read current manifest
55
+ const manifestPath = path.join(ws.layout.authoredRoot("pack"), packName, PACK_MANIFEST_FILENAME);
56
+ yield* ws.runTransaction({
57
+ targets: [manifestPath],
58
+ transition: Effect.gen(function* () {
59
+ const manifestContent = yield* fs.readFileString(manifestPath).pipe(Effect.mapError((e) => new AuthoringFailed({
60
+ category: "not_found",
61
+ detail: `Pack manifest not found at ${manifestPath}`,
62
+ suggestions: [{ description: "Ensure the pack exists on disk" }],
63
+ cause: e,
64
+ })));
65
+ // 3. Stale-check: compare content hash
66
+ const currentHash = hashContent(manifestContent);
67
+ if (currentHash !== manifestHash) {
68
+ return yield* new AuthoringFailed({
69
+ category: "conflict",
70
+ detail: `Pack manifest is stale — it was modified since the plan was created`,
71
+ suggestions: [{ description: "Re-run the command to create a fresh plan" }],
72
+ });
73
+ }
74
+ // 4. Parse and apply removals
75
+ const json = yield* Effect.try({
76
+ try: () => {
77
+ const parsed = JSON.parse(manifestContent);
78
+ return parsed;
79
+ },
80
+ catch: (e) => new AuthoringFailed({
81
+ category: "validation",
82
+ detail: `Failed to parse pack manifest: ${manifestPath}`,
83
+ cause: e,
84
+ }),
85
+ });
86
+ const manifest = yield* Schema.decodeUnknownEffect(PackManifestSchema)(json).pipe(Effect.mapError((e) => new AuthoringFailed({
87
+ category: "validation",
88
+ detail: `Invalid pack manifest: ${manifestPath}`,
89
+ cause: e,
90
+ })));
91
+ const removalSet = new Set(removals);
92
+ const dependencies = Object.fromEntries(Object.entries(manifest.dependencies).filter(([name]) => !removalSet.has(name)));
93
+ const updatedManifest = {
94
+ ...manifest,
95
+ owner: manifest.owner,
96
+ type: manifest.type,
97
+ name: manifest.name,
98
+ version: manifest.version,
99
+ dependencies,
100
+ };
101
+ const validatedUpdatedManifest = yield* Schema.decodeUnknownEffect(PackManifestSchema)(updatedManifest).pipe(Effect.mapError((cause) => new AuthoringFailed({
102
+ category: "validation",
103
+ detail: `Updated pack manifest is invalid: ${manifestPath}`,
104
+ cause,
105
+ })));
106
+ // 5. Write updated manifest
107
+ yield* fs
108
+ .writeFileString(manifestPath, JSON.stringify(validatedUpdatedManifest, null, 2) + "\n")
109
+ .pipe(Effect.mapError((e) => new AuthoringFailed({
110
+ category: "internal",
111
+ detail: `Failed to write pack manifest: ${manifestPath}`,
112
+ cause: e,
113
+ })));
114
+ }),
115
+ validate: () => fs.readFileString(manifestPath).pipe(Effect.flatMap((content) => Effect.try({
116
+ try: () => JSON.parse(content),
117
+ catch: (cause) => new AuthoringFailed({
118
+ category: "validation",
119
+ detail: `Updated pack manifest could not be parsed: ${manifestPath}`,
120
+ cause,
121
+ }),
122
+ })), Effect.flatMap(Schema.decodeUnknownEffect(PackManifestSchema)), Effect.flatMap((manifest) => removals.every((fqn) => manifest.dependencies[fqn] === undefined)
123
+ ? Effect.void
124
+ : new AuthoringFailed({
125
+ category: "internal",
126
+ detail: `Updated pack manifest retained a removed dependency`,
127
+ })), Effect.mapError((cause) => new AuthoringFailed({
128
+ category: "validation",
129
+ detail: `Updated pack manifest failed postcondition validation`,
130
+ cause,
131
+ }))),
132
+ });
133
+ return {
134
+ result: "success",
135
+ message: `Removed ${removals.length} extension${removals.length === 1 ? "" : "s"} from pack`,
136
+ artifact: packManifestArtifact({
137
+ owner: packOwner,
138
+ name: packName,
139
+ scope: ws.scope,
140
+ change: "updated",
141
+ fileCount: 1,
142
+ }),
143
+ };
144
+ }).pipe(withAdaptedStepFailures);
145
+ //# sourceMappingURL=remove-from-pack.js.map
@@ -0,0 +1,40 @@
1
+ /**
2
+ * New skill operation — scaffolds a new skill directory with manifest and SKILL.md.
3
+ *
4
+ * @experimental This API is unstable and may change without notice.
5
+ */
6
+ import * as FileSystem from "effect/FileSystem";
7
+ import * as Path from "effect/Path";
8
+ import { AuthoringFailureAdapter } from "../failure-adapter.js";
9
+ import type { Handle } from "@agentxm/extension-model/unstable/extensions/handle";
10
+ import type { OperationHandler } from "@agentxm/workspace-operations";
11
+ import type { Operation } from "@agentxm/workspace-operations";
12
+ import { WorkspaceMutations } from "@agentxm/workspace-state";
13
+ /**
14
+ * Args for the new-skill operation.
15
+ */
16
+ export interface NewSkillOperationArgs {
17
+ /** Skill name (validated, lowercase with hyphens). */
18
+ readonly name: string;
19
+ /** Profile (e.g., "@myorg"). */
20
+ readonly owner: Handle;
21
+ /** Agent IDs selected by the CLI. Install/materialization consumes workspace configuration. */
22
+ readonly agents: ReadonlyArray<string>;
23
+ }
24
+ /**
25
+ * Scaffold a new skill in the workspace.
26
+ *
27
+ * @experimental This API is unstable and may change without notice.
28
+ */
29
+ export type NewSkillOperation = Operation<"new-skill", NewSkillOperationArgs>;
30
+ /**
31
+ * New-skill operation handler.
32
+ *
33
+ * 1. Compute paths from the resolved workspace layout
34
+ * 2. Check if skill already exists in settings
35
+ * 3. Create skill directory (src/)
36
+ * 4. Write skill.json manifest
37
+ * 5. Write starter SKILL.md
38
+ */
39
+ export declare const newSkill: OperationHandler<NewSkillOperation, FileSystem.FileSystem | Path.Path | WorkspaceMutations | AuthoringFailureAdapter>;
40
+ //# sourceMappingURL=new-skill.d.ts.map
@@ -0,0 +1,102 @@
1
+ /**
2
+ * New skill operation — scaffolds a new skill directory with manifest and SKILL.md.
3
+ *
4
+ * @experimental This API is unstable and may change without notice.
5
+ */
6
+ import * as FileSystem from "effect/FileSystem";
7
+ import * as Path from "effect/Path";
8
+ import * as Effect from "effect/Effect";
9
+ import { AuthoringFailed } from "../errors.js";
10
+ import { AuthoringFailureAdapter, withAdaptedStepFailures } from "../failure-adapter.js";
11
+ import { createCanonicalDirectory, recoverCanonicalDirectory } from "@agentxm/extension-workspace";
12
+ import { preflightCreateOnly } from "../create-preflight.js";
13
+ import { decodeExtensionNameSync } from "@agentxm/extension-model/unstable/extensions";
14
+ import { WorkspaceMutations } from "@agentxm/workspace-state";
15
+ import { MANIFEST_FILENAME, MANIFEST_SCHEMA_URL, } from "@agentxm/extension-model/unstable/skills/manifest-schema";
16
+ import { decodeVersionSync } from "@agentxm/extension-model/unstable/version-constraints";
17
+ // -----------------------------------------------------------------------------
18
+ // Helpers
19
+ // -----------------------------------------------------------------------------
20
+ const makeSkillMd = (name) => `---
21
+ name: ${name}
22
+ description: Describe when this skill should be triggered by the agent
23
+ ---
24
+
25
+ Describe what this skill does and when to use it.
26
+ `;
27
+ const INITIAL_SKILL_VERSION = decodeVersionSync("0.0.1");
28
+ // -----------------------------------------------------------------------------
29
+ // Public API
30
+ // -----------------------------------------------------------------------------
31
+ /**
32
+ * New-skill operation handler.
33
+ *
34
+ * 1. Compute paths from the resolved workspace layout
35
+ * 2. Check if skill already exists in settings
36
+ * 3. Create skill directory (src/)
37
+ * 4. Write skill.json manifest
38
+ * 5. Write starter SKILL.md
39
+ */
40
+ export const newSkill = (op) => Effect.gen(function* () {
41
+ const fs = yield* FileSystem.FileSystem;
42
+ const path = yield* Path.Path;
43
+ const ws = yield* WorkspaceMutations;
44
+ const base = ws.baseDir;
45
+ if (ws.layout.scope !== "project") {
46
+ return yield* new AuthoringFailed({
47
+ category: "validation",
48
+ detail: "New skills can only be scaffolded in a project workspace",
49
+ });
50
+ }
51
+ const { name, owner } = op.args;
52
+ const fqn = `${owner}/skills/${name}`;
53
+ const configuredSkills = yield* ws.getConfiguredSkillEntries();
54
+ const canonicalPath = path.join(ws.layout.authoredRoot("skill"), name);
55
+ yield* recoverCanonicalDirectory({ baseDir: base, canonicalPath });
56
+ yield* preflightCreateOnly({
57
+ subject: "Skill",
58
+ name,
59
+ configured: Object.hasOwn(configuredSkills, name),
60
+ destinations: [canonicalPath],
61
+ });
62
+ const manifest = {
63
+ $schema: MANIFEST_SCHEMA_URL,
64
+ owner,
65
+ type: "skill",
66
+ name: decodeExtensionNameSync(name),
67
+ version: INITIAL_SKILL_VERSION,
68
+ };
69
+ yield* createCanonicalDirectory({
70
+ baseDir: base,
71
+ canonicalPath,
72
+ subject: "Skill",
73
+ requiredFiles: [MANIFEST_FILENAME, "src/SKILL.md"],
74
+ populate: (stagingPath) => {
75
+ const skillSrcPath = path.join(stagingPath, "src");
76
+ return Effect.gen(function* () {
77
+ yield* fs.makeDirectory(skillSrcPath, { recursive: true }).pipe(Effect.mapError((e) => new AuthoringFailed({
78
+ category: "validation",
79
+ detail: `Failed to create skill directory: ${skillSrcPath}`,
80
+ cause: e,
81
+ })));
82
+ yield* fs
83
+ .writeFileString(path.join(stagingPath, MANIFEST_FILENAME), JSON.stringify(manifest, null, 2) + "\n")
84
+ .pipe(Effect.mapError((e) => new AuthoringFailed({
85
+ category: "validation",
86
+ detail: "Skill manifest could not be written",
87
+ cause: e,
88
+ })));
89
+ yield* fs.writeFileString(path.join(skillSrcPath, "SKILL.md"), makeSkillMd(name)).pipe(Effect.mapError((e) => new AuthoringFailed({
90
+ category: "validation",
91
+ detail: "Failed to write SKILL.md",
92
+ cause: e,
93
+ })));
94
+ });
95
+ },
96
+ });
97
+ return {
98
+ result: "success",
99
+ message: `Created skill ${fqn}`,
100
+ };
101
+ }).pipe(withAdaptedStepFailures);
102
+ //# sourceMappingURL=new-skill.js.map
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@agentxm/extension-authoring",
3
+ "version": "0.28.4-bootstrap.0",
4
+ "description": "AXM extension-authoring feature: new-extension scaffolding, fork, native import, adopt/demote identity policy, and authored pack membership for the axm CLI. Unstable and unsupported — use the axm.sh CLI.",
5
+ "type": "module",
6
+ "license": "FSL-1.1-MIT",
7
+ "homepage": "https://axm.sh",
8
+ "bugs": {
9
+ "url": "https://github.com/agentxm/axm/issues"
10
+ },
11
+ "author": "AgentXM <hello@agentxm.ai> (https://agentxm.ai)",
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "https://github.com/agentxm/axm.git",
15
+ "directory": "packages/extension-authoring"
16
+ },
17
+ "sideEffects": false,
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/src/index.d.ts",
21
+ "default": "./dist/src/index.js"
22
+ }
23
+ },
24
+ "files": [
25
+ "dist/src/",
26
+ "!**/*.map"
27
+ ],
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
31
+ "engines": {
32
+ "node": ">=22.19.0"
33
+ },
34
+ "nx": {
35
+ "includedScripts": []
36
+ },
37
+ "dependencies": {
38
+ "effect": "4.0.0-rc.112",
39
+ "yaml": "^2.9.0",
40
+ "@agentxm/extension-model": "^0.28.4-bootstrap.0",
41
+ "@agentxm/registry-protocol": "^0.28.4-bootstrap.0",
42
+ "@agentxm/workspace-state": "^0.28.4-bootstrap.0",
43
+ "@agentxm/workspace-operations": "^0.28.4-bootstrap.0",
44
+ "@agentxm/extension-workspace": "^0.28.4-bootstrap.0"
45
+ },
46
+ "devDependencies": {
47
+ "@effect/platform-node": "4.0.0-rc.112",
48
+ "@effect/vitest": "4.0.0-rc.112",
49
+ "@types/bun": "^1.3.14",
50
+ "@typescript/native": "npm:typescript@^7.0.2",
51
+ "typescript": "npm:@typescript/typescript6@^6.0.2",
52
+ "vitest": "^4.1.10"
53
+ }
54
+ }