@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.
- package/LICENSE +110 -0
- package/dist/src/create-preflight.d.ts +12 -0
- package/dist/src/create-preflight.js +19 -0
- package/dist/src/desired-identity.d.ts +19 -0
- package/dist/src/desired-identity.js +26 -0
- package/dist/src/errors.d.ts +29 -0
- package/dist/src/errors.js +28 -0
- package/dist/src/failure-adapter.d.ts +31 -0
- package/dist/src/failure-adapter.js +23 -0
- package/dist/src/fork-package.d.ts +20 -0
- package/dist/src/fork-package.js +155 -0
- package/dist/src/hooks/new-hook.d.ts +46 -0
- package/dist/src/hooks/new-hook.js +164 -0
- package/dist/src/import-native-package.d.ts +14 -0
- package/dist/src/import-native-package.js +135 -0
- package/dist/src/index.d.ts +22 -0
- package/dist/src/index.js +24 -0
- package/dist/src/marker-fqn.d.ts +23 -0
- package/dist/src/marker-fqn.js +10 -0
- package/dist/src/packs/add-to-pack.d.ts +44 -0
- package/dist/src/packs/add-to-pack.js +147 -0
- package/dist/src/packs/artifact.d.ts +13 -0
- package/dist/src/packs/artifact.js +17 -0
- package/dist/src/packs/hash-content.d.ts +2 -0
- package/dist/src/packs/hash-content.js +3 -0
- package/dist/src/packs/new-pack.d.ts +37 -0
- package/dist/src/packs/new-pack.js +90 -0
- package/dist/src/packs/remove-from-pack.d.ts +44 -0
- package/dist/src/packs/remove-from-pack.js +145 -0
- package/dist/src/skills/new-skill.d.ts +40 -0
- package/dist/src/skills/new-skill.js +102 -0
- package/package.json +54 -0
|
@@ -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
|
+
}
|