@agentxm/extension-model 0.38.0 → 0.39.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.
Files changed (65) hide show
  1. package/dist/src/unstable/agent-capabilities/catalog.d.ts +1820 -96
  2. package/dist/src/unstable/agent-capabilities/catalog.js +2 -1
  3. package/dist/src/unstable/agent-capabilities/data/agents/augment.d.ts +1 -1
  4. package/dist/src/unstable/agent-capabilities/data/agents/augment.js +1 -1
  5. package/dist/src/unstable/agent-capabilities/data/agents/claude-code.d.ts +21 -3
  6. package/dist/src/unstable/agent-capabilities/data/agents/claude-code.js +18 -3
  7. package/dist/src/unstable/agent-capabilities/data/agents/codebuddy.d.ts +1 -1
  8. package/dist/src/unstable/agent-capabilities/data/agents/codebuddy.js +1 -1
  9. package/dist/src/unstable/agent-capabilities/data/agents/codex.d.ts +3 -2
  10. package/dist/src/unstable/agent-capabilities/data/agents/codex.js +3 -2
  11. package/dist/src/unstable/agent-capabilities/data/agents/cursor.d.ts +186 -10
  12. package/dist/src/unstable/agent-capabilities/data/agents/cursor.js +223 -10
  13. package/dist/src/unstable/agent-capabilities/data/agents/deepagents.d.ts +1 -1
  14. package/dist/src/unstable/agent-capabilities/data/agents/deepagents.js +1 -1
  15. package/dist/src/unstable/agent-capabilities/data/agents/gemini-cli.d.ts +1 -1
  16. package/dist/src/unstable/agent-capabilities/data/agents/gemini-cli.js +1 -1
  17. package/dist/src/unstable/agent-capabilities/data/agents/github-copilot-cli.d.ts +19 -1
  18. package/dist/src/unstable/agent-capabilities/data/agents/github-copilot-cli.js +16 -1
  19. package/dist/src/unstable/agent-capabilities/data/agents/ibm-bob.d.ts +1 -1
  20. package/dist/src/unstable/agent-capabilities/data/agents/ibm-bob.js +1 -1
  21. package/dist/src/unstable/agent-capabilities/data/agents/index.d.ts +1 -0
  22. package/dist/src/unstable/agent-capabilities/data/agents/index.js +1 -0
  23. package/dist/src/unstable/agent-capabilities/data/agents/kiro-cli.d.ts +1 -1
  24. package/dist/src/unstable/agent-capabilities/data/agents/kiro-cli.js +1 -1
  25. package/dist/src/unstable/agent-capabilities/data/agents/opencode.d.ts +2 -1
  26. package/dist/src/unstable/agent-capabilities/data/agents/opencode.js +2 -1
  27. package/dist/src/unstable/agent-capabilities/data/agents/pi.d.ts +105 -6
  28. package/dist/src/unstable/agent-capabilities/data/agents/pi.js +77 -6
  29. package/dist/src/unstable/agent-capabilities/data/agents/qoder.d.ts +1 -1
  30. package/dist/src/unstable/agent-capabilities/data/agents/qoder.js +1 -1
  31. package/dist/src/unstable/agent-capabilities/data/agents/qwen-code.d.ts +1 -1
  32. package/dist/src/unstable/agent-capabilities/data/agents/qwen-code.js +1 -1
  33. package/dist/src/unstable/agent-capabilities/data/agents/roo.d.ts +1 -1
  34. package/dist/src/unstable/agent-capabilities/data/agents/roo.js +1 -1
  35. package/dist/src/unstable/agent-capabilities/data/agents/vscode.d.ts +263 -0
  36. package/dist/src/unstable/agent-capabilities/data/agents/vscode.js +139 -0
  37. package/dist/src/unstable/agent-capabilities/derive.d.ts +14 -22
  38. package/dist/src/unstable/agent-capabilities/derive.js +40 -51
  39. package/dist/src/unstable/agent-capabilities/identity.d.ts +3 -3
  40. package/dist/src/unstable/agent-capabilities/identity.js +1 -0
  41. package/dist/src/unstable/agent-capabilities/schema.d.ts +50 -12
  42. package/dist/src/unstable/agent-capabilities/schema.js +10 -2
  43. package/dist/src/unstable/agents/types.d.ts +1 -1
  44. package/dist/src/unstable/extensions/common.d.ts +17 -3
  45. package/dist/src/unstable/extensions/common.js +8 -8
  46. package/dist/src/unstable/extensions/installable-types.d.ts +2 -2
  47. package/dist/src/unstable/extensions/refs/mcp-server.d.ts +16 -2
  48. package/dist/src/unstable/extensions/refs/mcp-server.js +12 -1
  49. package/dist/src/unstable/extensions/refs/ref-base.d.ts +17 -2
  50. package/dist/src/unstable/extensions/refs/ref-base.js +16 -1
  51. package/dist/src/unstable/extensions/refs/skill.d.ts +14 -2
  52. package/dist/src/unstable/extensions/refs/skill.js +0 -9
  53. package/dist/src/unstable/hooks/manifest-schema.d.ts +221 -105
  54. package/dist/src/unstable/hooks/manifest-schema.js +271 -87
  55. package/dist/src/unstable/hooks/resolution.d.ts +24 -0
  56. package/dist/src/unstable/hooks/resolution.js +99 -0
  57. package/dist/src/unstable/sources/http-artifact.d.ts +24 -0
  58. package/dist/src/unstable/sources/http-artifact.js +46 -0
  59. package/dist/src/unstable/sources/printer.js +14 -1
  60. package/dist/src/unstable/sources/source-host-provider.d.ts +3 -0
  61. package/dist/src/unstable/sources/types.d.ts +16 -6
  62. package/dist/src/unstable/sources/types.js +2 -0
  63. package/dist/src/unstable/subagents/manifest-schema.d.ts +48 -18
  64. package/dist/src/unstable/subagents/manifest-schema.js +85 -18
  65. package/package.json +10 -2
@@ -1,112 +1,296 @@
1
- /**
2
- * Hook manifest schema definition.
3
- *
4
- * @experimental This API is unstable and may change without notice.
5
- */
1
+ /** Native Hook package contract. @experimental */
2
+ import * as Result from "effect/Result";
6
3
  import * as Schema from "effect/Schema";
7
- import { CanonicalHookEventIdSchema, CanonicalHookToolIdSchema, HookBlockOutcomeSchema, HookModifyOperationSchema, } from "../agent-capabilities/schema.js";
8
- import { CommonManifestBaseFields, ExtensionNameSchema, NonPackManifestFields, } from "../extensions/common.js";
4
+ import { HookBlockOutcomeSchema, HookModifyOperationSchema } from "../agent-capabilities/schema.js";
5
+ import { CommonManifestBaseFields, ConfigurableAgentIdSchema, ExtensionNameSchema, NonPackManifestFields, } from "../extensions/common.js";
6
+ import { VersionRangeSchema } from "../version-constraints/version-constraints.js";
9
7
  export const HOOK_MANIFEST_FILENAME = "hook.json";
10
8
  export const HOOK_EXTENSION_DIR = "hooks";
11
9
  export const HOOK_MANIFEST_SCHEMA_URL = "https://axm.sh/schemas/hook.schema.json";
12
10
  export const HookRuntimeSchema = Schema.Literals(["bash", "node", "python"]).annotate({
13
11
  identifier: "HookRuntime",
14
- title: "Hook Runtime",
15
- description: "Interpreter family used to execute the materialized hook entrypoint.",
12
+ description: "Interpreter family used to execute this native command handler.",
16
13
  });
17
- export const HookEventSchema = CanonicalHookEventIdSchema.annotate({
18
- identifier: "HookEvent",
19
- title: "Hook Event",
20
- description: "Canonical AXM hook event this extension binds to.",
21
- });
22
- export const HookMatchSchema = Schema.Struct({
23
- tools: Schema.optional(Schema.NonEmptyArray(CanonicalHookToolIdSchema).pipe(Schema.check(Schema.isUnique()))),
24
- }).annotate({
25
- identifier: "HookMatch",
26
- title: "Hook Match",
27
- description: "Portable hook matcher expressed over AXM canonical tool IDs.",
14
+ const HookIdSchema = Schema.NonEmptyString.check(Schema.isPattern(/^[a-z][a-z0-9-]*$/), Schema.isMaxLength(80));
15
+ const ConfigurationKeySchema = Schema.NonEmptyString.check(Schema.isPattern(/^[a-zA-Z][a-zA-Z0-9_]*$/), Schema.isMaxLength(64));
16
+ const EnvironmentKeySchema = Schema.NonEmptyString.check(Schema.isPattern(/^[a-zA-Z_][a-zA-Z0-9_]*$/));
17
+ export const HookPackagePathSchema = Schema.NonEmptyString.check(Schema.isPattern(
18
+ // eslint-disable-next-line no-control-regex -- Package paths must reject control characters, including NUL.
19
+ /^(?!\/)(?!.*(?:^|\/)\.{1,2}(?:\/|$))(?!.*\/\/)(?!.*[\\:\u0000-\u001f])[^/]+(?:\/[^/]+)*$/)).annotate({
20
+ identifier: "HookPackagePath",
21
+ description: "A safe, package-relative POSIX file path. Absolute paths and traversal are forbidden.",
28
22
  });
29
- export const HookDecisionRequirementSchema = Schema.Union([
30
- Schema.Struct({ kind: Schema.Literal("observe") }),
23
+ /** Symbolic references are preserved, never resolved against the author's environment. */
24
+ export const HookEnvironmentReferenceSchema = Schema.Struct({ env: EnvironmentKeySchema });
25
+ export const HookValueSchema = Schema.Union([
26
+ Schema.String,
27
+ Schema.Struct({ config: ConfigurationKeySchema }),
28
+ HookEnvironmentReferenceSchema,
29
+ ]).annotate({ identifier: "HookValue" });
30
+ export const HookConfigurationValueSchema = Schema.Union([
31
+ Schema.String,
32
+ Schema.Finite,
33
+ Schema.Boolean,
34
+ HookEnvironmentReferenceSchema,
35
+ ]);
36
+ export const HookConfigurationValuesSchema = Schema.Record(ConfigurationKeySchema, HookConfigurationValueSchema);
37
+ const ConfigurationFields = {
38
+ description: Schema.optional(Schema.NonEmptyString),
39
+ required: Schema.optional(Schema.Boolean),
40
+ };
41
+ export const HookConfigurationFieldSchema = Schema.Union([
31
42
  Schema.Struct({
32
- kind: Schema.Literal("block"),
33
- outcomes: Schema.optional(Schema.NonEmptyArray(HookBlockOutcomeSchema).pipe(Schema.check(Schema.isUnique()))),
43
+ ...ConfigurationFields,
44
+ type: Schema.Literal("string"),
45
+ default: Schema.optional(Schema.String),
46
+ secret: Schema.optional(Schema.Boolean),
47
+ allowEmpty: Schema.optional(Schema.Boolean),
48
+ minLength: Schema.optional(Schema.Int.check(Schema.isGreaterThanOrEqualTo(0))),
49
+ maxLength: Schema.optional(Schema.Int.check(Schema.isGreaterThanOrEqualTo(0))),
34
50
  }),
35
51
  Schema.Struct({
36
- kind: Schema.Literal("modify"),
37
- operations: Schema.optional(Schema.NonEmptyArray(HookModifyOperationSchema).pipe(Schema.check(Schema.isUnique()))),
52
+ ...ConfigurationFields,
53
+ type: Schema.Literal("number"),
54
+ default: Schema.optional(Schema.Finite),
55
+ minimum: Schema.optional(Schema.Finite),
56
+ maximum: Schema.optional(Schema.Finite),
38
57
  }),
39
- ]).annotate({
40
- identifier: "HookDecisionRequirement",
41
- title: "Hook Decision Requirement",
42
- description: "Decision capability a hook binding requires from the target agent event.",
43
- });
44
- export const HookBindingTargetSchema = Schema.Struct({
45
- matcherRaw: Schema.optional(Schema.NonEmptyString),
58
+ Schema.Struct({
59
+ ...ConfigurationFields,
60
+ type: Schema.Literal("boolean"),
61
+ default: Schema.optional(Schema.Boolean),
62
+ }),
63
+ Schema.Struct({
64
+ ...ConfigurationFields,
65
+ type: Schema.Literal("enum"),
66
+ values: Schema.NonEmptyArray(Schema.NonEmptyString).check(Schema.isUnique()),
67
+ default: Schema.optional(Schema.NonEmptyString),
68
+ }),
69
+ ]).annotate({ identifier: "HookConfigurationField" });
70
+ export const HookBindingRequirementsSchema = Schema.Struct({
71
+ outcomes: Schema.optional(Schema.NonEmptyArray(HookBlockOutcomeSchema).check(Schema.isUnique())),
72
+ operations: Schema.optional(Schema.NonEmptyArray(HookModifyOperationSchema).check(Schema.isUnique())),
46
73
  }).annotate({
47
- identifier: "HookBindingTarget",
48
- title: "Hook Binding Target",
49
- description: "Target-agent-specific hook binding escape hatches.",
74
+ identifier: "HookBindingRequirements",
75
+ description: "Every declared outcome and operation must be supported by this native event. Omit for observation only.",
76
+ });
77
+ export const HookCommandHandlerSchema = Schema.Struct({
78
+ type: Schema.Literal("command"),
79
+ name: Schema.optional(Schema.NonEmptyString),
80
+ runtime: HookRuntimeSchema,
81
+ entrypoint: HookPackagePathSchema,
82
+ args: Schema.optional(Schema.Array(HookValueSchema)),
83
+ env: Schema.optional(Schema.Record(EnvironmentKeySchema, HookValueSchema)),
84
+ timeoutMs: Schema.optional(Schema.Int.check(Schema.isGreaterThan(0))),
85
+ }).annotate({ identifier: "HookCommandHandler" });
86
+ export const HookEventSchema = Schema.NonEmptyString.check(Schema.isPattern(/^[a-zA-Z][a-zA-Z0-9_.:-]*$/)).annotate({
87
+ identifier: "HookEvent",
88
+ description: "Exact event name in the implementation's native host protocol.",
50
89
  });
51
- export const CanonicalHookBindingSchema = Schema.Struct({
52
- on: HookEventSchema,
53
- match: Schema.optional(HookMatchSchema),
54
- matcherRaw: Schema.optional(Schema.NonEmptyString),
55
- targets: Schema.optional(Schema.Record(Schema.String, HookBindingTargetSchema)),
90
+ export const HookBindingSchema = Schema.Struct({
91
+ id: HookIdSchema,
92
+ event: HookEventSchema,
93
+ matcher: Schema.optional(Schema.NonEmptyString),
94
+ handler: HookCommandHandlerSchema,
95
+ requires: Schema.optional(HookBindingRequirementsSchema),
96
+ }).annotate({ identifier: "HookBinding" });
97
+ export const HookImplementationSchema = Schema.Struct({
98
+ id: HookIdSchema,
99
+ protocol: ConfigurableAgentIdSchema,
56
100
  requires: Schema.optional(Schema.Struct({
57
- decision: HookDecisionRequirementSchema,
101
+ hostVersion: Schema.optional(VersionRangeSchema),
102
+ profiles: Schema.optional(Schema.NonEmptyArray(Schema.NonEmptyString).check(Schema.isUnique())),
103
+ platforms: Schema.optional(Schema.NonEmptyArray(Schema.Literals(["darwin", "linux", "win32"])).check(Schema.isUnique())),
104
+ scopes: Schema.optional(Schema.NonEmptyArray(Schema.Literals(["project", "user"])).check(Schema.isUnique())),
58
105
  })),
106
+ bindings: Schema.NonEmptyArray(HookBindingSchema),
107
+ }).annotate({ identifier: "HookImplementation" });
108
+ export const HookFixtureSchema = Schema.Struct({
109
+ id: HookIdSchema,
110
+ implementation: HookIdSchema,
111
+ binding: HookIdSchema,
112
+ input: HookPackagePathSchema,
113
+ expect: Schema.Struct({
114
+ exitCode: Schema.Int.check(Schema.isBetween({ minimum: 0, maximum: 255 })),
115
+ stdout: Schema.optional(HookPackagePathSchema),
116
+ stderr: Schema.optional(HookPackagePathSchema),
117
+ }),
59
118
  }).annotate({
60
- identifier: "CanonicalHookBinding",
61
- title: "Canonical Hook Binding",
62
- description: "Universal hook event binding expressed in AXM canonical vocabulary.",
63
- });
64
- export const HookBindingSchema = CanonicalHookBindingSchema.annotate({
65
- identifier: "HookBinding",
66
- title: "Hook Binding",
67
- description: "Universal hook event binding with portable canonical matching and raw native escape hatches.",
68
- });
69
- export const HookCapabilitiesSchema = Schema.Struct({
70
- network: Schema.optional(Schema.Boolean),
71
- filesystemWrite: Schema.optional(Schema.Boolean),
72
- exec: Schema.optional(Schema.Array(Schema.NonEmptyString)),
73
- env: Schema.optional(Schema.Array(Schema.NonEmptyString)),
74
- }).annotate({
75
- identifier: "HookCapabilities",
76
- title: "Hook Capabilities",
77
- description: "Advisory author-declared hook capability surface. v1 does not enforce it.",
119
+ identifier: "HookFixture",
120
+ description: "Native stdin and expected output files used only by explicitly requested fixture execution.",
78
121
  });
79
- /**
80
- * Schema for hook manifest files (hook.json).
81
- *
82
- * Hooks distribute an executable body plus agent event bindings. Install
83
- * materializes the body under agent_extensions and registers native agent hook
84
- * settings that invoke the materialized entrypoint.
85
- *
86
- * @experimental This API is unstable and may change without notice.
87
- */
88
- export const HookManifestSchema = Schema.Struct({
122
+ const HookManifestStruct = Schema.Struct({
89
123
  $schema: Schema.optional(Schema.String),
90
124
  ...CommonManifestBaseFields,
91
- ...NonPackManifestFields,
125
+ enhances: NonPackManifestFields.enhances,
126
+ requires: NonPackManifestFields.requires,
127
+ recommendedPacks: NonPackManifestFields.recommendedPacks,
128
+ standalone: NonPackManifestFields.standalone,
92
129
  type: Schema.Literal("hook"),
93
- name: ExtensionNameSchema.pipe(Schema.annotateKey({ messageMissingKey: "hook name is required" }), Schema.annotate({
94
- description: "Short name for this hook within its owner namespace. Combined with owner, forms the FQN @owner/hooks/<name>.",
95
- })),
96
- title: Schema.optional(Schema.NonEmptyString.annotate({
97
- description: "Optional display title for this hook.",
98
- })),
99
- runtime: HookRuntimeSchema.pipe(Schema.annotateKey({ messageMissingKey: "runtime is required" })),
100
- entrypoint: Schema.NonEmptyString.pipe(Schema.annotateKey({ messageMissingKey: "entrypoint is required" }), Schema.annotate({
101
- description: "Hook body entrypoint path, relative to the hook manifest directory.",
102
- examples: ["src/hook.sh", "src/hook.js", "src/hook.py"],
103
- })),
104
- bindings: Schema.Array(HookBindingSchema).pipe(Schema.annotateKey({ messageMissingKey: "bindings are required" })),
105
- timeoutMs: Schema.optional(Schema.Int.pipe(Schema.check(Schema.isGreaterThan(0)))),
106
- capabilities: Schema.optional(HookCapabilitiesSchema),
107
- }).annotate({
130
+ name: ExtensionNameSchema,
131
+ title: Schema.optional(Schema.NonEmptyString),
132
+ implementations: Schema.NonEmptyArray(HookImplementationSchema),
133
+ configuration: Schema.optional(Schema.Record(ConfigurationKeySchema, HookConfigurationFieldSchema)),
134
+ assets: Schema.optional(Schema.Array(HookPackagePathSchema).check(Schema.isUnique())),
135
+ fixtures: Schema.optional(Schema.Array(HookFixtureSchema)),
136
+ });
137
+ const configurationValueProblem = (field, value) => {
138
+ if (field.type === "string" && field.secret === true) {
139
+ return typeof value === "object"
140
+ ? undefined
141
+ : "Secret configuration requires a symbolic environment reference.";
142
+ }
143
+ if (typeof value === "object")
144
+ return "Environment references are only accepted by secret string configuration.";
145
+ switch (field.type) {
146
+ case "string":
147
+ if (typeof value !== "string")
148
+ return "Expected a string.";
149
+ if (value.length === 0 && field.allowEmpty !== true)
150
+ return "An empty string is not allowed.";
151
+ if (field.minLength !== undefined && value.length < field.minLength)
152
+ return "String is shorter than minLength.";
153
+ if (field.maxLength !== undefined && value.length > field.maxLength)
154
+ return "String is longer than maxLength.";
155
+ return undefined;
156
+ case "boolean":
157
+ return typeof value === "boolean" ? undefined : "Expected a boolean.";
158
+ case "number":
159
+ if (typeof value !== "number" || !Number.isFinite(value))
160
+ return "Expected a finite number.";
161
+ if (field.minimum !== undefined && value < field.minimum)
162
+ return "Number is below minimum.";
163
+ if (field.maximum !== undefined && value > field.maximum)
164
+ return "Number exceeds maximum.";
165
+ return undefined;
166
+ case "enum":
167
+ return typeof value === "string" && field.values.includes(value)
168
+ ? undefined
169
+ : "Expected a declared enum value.";
170
+ }
171
+ };
172
+ export const HookManifestSchema = HookManifestStruct.check(Schema.makeFilter((manifest) => {
173
+ const issues = [];
174
+ const implementationIds = new Set();
175
+ for (const [index, implementation] of manifest.implementations.entries()) {
176
+ if (implementationIds.has(implementation.id))
177
+ issues.push({
178
+ path: ["implementations", index, "id"],
179
+ issue: "Implementation IDs must be unique.",
180
+ });
181
+ implementationIds.add(implementation.id);
182
+ const bindingIds = new Set();
183
+ for (const [bindingIndex, binding] of implementation.bindings.entries()) {
184
+ if (bindingIds.has(binding.id))
185
+ issues.push({
186
+ path: ["implementations", index, "bindings", bindingIndex, "id"],
187
+ issue: "Binding IDs must be unique within an implementation.",
188
+ });
189
+ bindingIds.add(binding.id);
190
+ for (const value of [
191
+ ...(binding.handler.args ?? []),
192
+ ...Object.values(binding.handler.env ?? {}),
193
+ ]) {
194
+ if (typeof value === "object" &&
195
+ "config" in value &&
196
+ !Object.hasOwn(manifest.configuration ?? {}, value.config)) {
197
+ issues.push({
198
+ path: ["implementations", index, "bindings", bindingIndex, "handler"],
199
+ issue: `Unknown configuration reference: ${value.config}.`,
200
+ });
201
+ }
202
+ }
203
+ }
204
+ }
205
+ for (const [key, field] of Object.entries(manifest.configuration ?? {})) {
206
+ if (field.default !== undefined) {
207
+ const problem = configurationValueProblem(field, field.default);
208
+ if (problem !== undefined)
209
+ issues.push({ path: ["configuration", key, "default"], issue: problem });
210
+ }
211
+ if (field.type === "string" &&
212
+ field.minLength !== undefined &&
213
+ field.maxLength !== undefined &&
214
+ field.minLength > field.maxLength)
215
+ issues.push({
216
+ path: ["configuration", key],
217
+ issue: "minLength must not exceed maxLength.",
218
+ });
219
+ if (field.type === "number" &&
220
+ field.minimum !== undefined &&
221
+ field.maximum !== undefined &&
222
+ field.minimum > field.maximum)
223
+ issues.push({ path: ["configuration", key], issue: "minimum must not exceed maximum." });
224
+ }
225
+ const fixtureIds = new Set();
226
+ for (const [index, fixture] of (manifest.fixtures ?? []).entries()) {
227
+ if (fixtureIds.has(fixture.id))
228
+ issues.push({ path: ["fixtures", index, "id"], issue: "Fixture IDs must be unique." });
229
+ fixtureIds.add(fixture.id);
230
+ const implementation = manifest.implementations.find((entry) => entry.id === fixture.implementation);
231
+ if (implementation === undefined ||
232
+ !implementation.bindings.some((entry) => entry.id === fixture.binding))
233
+ issues.push({
234
+ path: ["fixtures", index],
235
+ issue: "Fixture must reference an existing implementation and binding.",
236
+ });
237
+ }
238
+ return issues;
239
+ })).annotate({
108
240
  identifier: "HookManifest",
109
241
  title: "Hook Manifest",
110
- description: "Hook manifest for managed agent hooks. The executable body lives under src/ and is invoked from native agent settings.",
242
+ description: "A package of explicit native Hook implementations, shared assets, typed consumer configuration, and optional native protocol fixtures. AXM installs native settings; it does not translate payloads or execute hook bodies during lifecycle operations.",
111
243
  });
244
+ /** Files required to install and activate any declared implementation. */
245
+ export const requiredHookRuntimeFiles = (manifest) => [
246
+ ...new Set([
247
+ ...(manifest.assets ?? []),
248
+ ...manifest.implementations.flatMap((implementation) => implementation.bindings.map((binding) => binding.handler.entrypoint)),
249
+ ]),
250
+ ];
251
+ /** Source-authoring closure; fixtures may be omitted from a distributed package. */
252
+ export const referencedHookPackageFiles = (manifest) => [
253
+ ...new Set([
254
+ ...requiredHookRuntimeFiles(manifest),
255
+ ...(manifest.fixtures ?? []).flatMap((fixture) => [
256
+ fixture.input,
257
+ ...(fixture.expect.stdout === undefined ? [] : [fixture.expect.stdout]),
258
+ ...(fixture.expect.stderr === undefined ? [] : [fixture.expect.stderr]),
259
+ ]),
260
+ ]),
261
+ ];
262
+ /** Explicit consumer values override author defaults; no source objects are mutated. */
263
+ export const resolveHookConfiguration = (manifest, values = {}) => {
264
+ const fields = manifest.configuration ?? {};
265
+ const issues = [];
266
+ const resolved = {};
267
+ for (const key of Object.keys(values))
268
+ if (!Object.hasOwn(fields, key))
269
+ issues.push({ key, code: "unknown", message: "Unknown hook configuration key." });
270
+ for (const [key, field] of Object.entries(fields)) {
271
+ const input = Object.hasOwn(values, key) ? values[key] : field.default;
272
+ if (input === undefined) {
273
+ if (field.required === true)
274
+ issues.push({ key, code: "missing", message: "Required hook configuration is missing." });
275
+ continue;
276
+ }
277
+ const decoded = Schema.decodeUnknownResult(HookConfigurationValueSchema)(input, {
278
+ onExcessProperty: "error",
279
+ });
280
+ if (Result.isFailure(decoded)) {
281
+ issues.push({
282
+ key,
283
+ code: "invalid",
284
+ message: "Expected a scalar value or symbolic environment reference.",
285
+ });
286
+ continue;
287
+ }
288
+ const problem = configurationValueProblem(field, decoded.success);
289
+ if (problem !== undefined)
290
+ issues.push({ key, code: "invalid", message: problem });
291
+ else
292
+ resolved[key] = decoded.success;
293
+ }
294
+ return issues.length > 0 ? Result.fail(issues) : Result.succeed(resolved);
295
+ };
112
296
  //# sourceMappingURL=manifest-schema.js.map
@@ -0,0 +1,24 @@
1
+ import type { ConfigurableAgentId } from "../agent-capabilities/identity.js";
2
+ import type { WorkspaceScope } from "../workspace-scope.js";
3
+ import type { HookManifest, HookImplementation } from "./manifest-schema.js";
4
+ export interface HookImplementationContext {
5
+ readonly scope: WorkspaceScope;
6
+ readonly platform?: string;
7
+ readonly hostVersion?: string;
8
+ readonly profile?: string;
9
+ readonly availableRuntimes?: ReadonlyArray<"bash" | "node" | "python">;
10
+ }
11
+ export type HookImplementationResolution = {
12
+ readonly status: "selected" | "conditional";
13
+ readonly implementation: HookImplementation;
14
+ readonly conditions: ReadonlyArray<string>;
15
+ } | {
16
+ readonly status: "unsupported";
17
+ readonly reasons: ReadonlyArray<string>;
18
+ } | {
19
+ readonly status: "ambiguous";
20
+ readonly implementationIds: ReadonlyArray<string>;
21
+ };
22
+ /** Select declared implementations without treating unknown host facts as verified support. */
23
+ export declare const resolveHookImplementation: (manifest: HookManifest, agentId: ConfigurableAgentId, context: HookImplementationContext) => HookImplementationResolution;
24
+ //# sourceMappingURL=resolution.d.ts.map
@@ -0,0 +1,99 @@
1
+ /** Exact native Hook realization selection, shared by projection and discovery. @experimental */
2
+ import * as semver from "semver";
3
+ import { installable } from "../agent-capabilities/derive.js";
4
+ import { agentById } from "../agent-capabilities/lookup.js";
5
+ /** Select declared implementations without treating unknown host facts as verified support. */
6
+ export const resolveHookImplementation = (manifest, agentId, context) => {
7
+ // Native command serialization currently uses POSIX shell quoting and expansion.
8
+ if (context.platform !== undefined &&
9
+ context.platform !== "linux" &&
10
+ context.platform !== "darwin")
11
+ return {
12
+ status: "unsupported",
13
+ reasons: [
14
+ `Native Hook command serialization is unavailable on ${context.platform}; supported platforms are linux and darwin.`,
15
+ ],
16
+ };
17
+ const agent = agentById(agentId);
18
+ const hook = agent.capabilities.hook;
19
+ const writer = hook.axm.writer;
20
+ if (writer === null ||
21
+ !("locations" in hook.native) ||
22
+ !hook.native.locations.some((location) => location.scope === context.scope && writer.locationIds.includes(location.id)))
23
+ return {
24
+ status: "unsupported",
25
+ reasons: [`No native Hook writer supports ${agentId} at ${context.scope} scope.`],
26
+ };
27
+ const candidates = [];
28
+ const reasons = [];
29
+ for (const implementation of manifest.implementations) {
30
+ if (implementation.protocol !== agentId)
31
+ continue;
32
+ const failures = implementation.bindings
33
+ .map((binding) => installable(agent, binding))
34
+ .filter((verdict) => !verdict.installable);
35
+ if (failures.length > 0) {
36
+ reasons.push(...failures.map((failure) => `${implementation.id}: ${failure.reason}`));
37
+ continue;
38
+ }
39
+ const required = implementation.requires;
40
+ if (required?.scopes !== undefined && !required.scopes.includes(context.scope)) {
41
+ reasons.push(`${implementation.id} does not support ${context.scope} scope.`);
42
+ continue;
43
+ }
44
+ const conditions = context.platform === undefined
45
+ ? ["Platform must support the native POSIX command serializer (linux or darwin)."]
46
+ : [];
47
+ let excluded = false;
48
+ const runtimes = [
49
+ ...new Set(implementation.bindings.map((binding) => binding.handler.runtime)),
50
+ ];
51
+ if (context.availableRuntimes === undefined)
52
+ conditions.push(`Native host environment must provide: ${runtimes.map((runtime) => (runtime === "python" ? "python3" : runtime)).join(", ")}; availability is unverified.`);
53
+ else if (runtimes.some((runtime) => !context.availableRuntimes?.includes(runtime))) {
54
+ reasons.push(`${implementation.id} requires unavailable runtimes: ${runtimes.filter((runtime) => !context.availableRuntimes?.includes(runtime)).join(", ")}.`);
55
+ excluded = true;
56
+ }
57
+ if (required?.platforms !== undefined) {
58
+ if (context.platform === undefined)
59
+ conditions.push(`Platform must be one of: ${required.platforms.join(", ")}.`);
60
+ else if (!required.platforms.some((platform) => platform === context.platform)) {
61
+ reasons.push(`${implementation.id} does not support ${context.platform}.`);
62
+ excluded = true;
63
+ }
64
+ }
65
+ if (required?.profiles !== undefined) {
66
+ if (context.profile === undefined)
67
+ conditions.push(`Host profile must be one of: ${required.profiles.join(", ")}.`);
68
+ else if (!required.profiles.includes(context.profile)) {
69
+ reasons.push(`${implementation.id} does not support profile ${context.profile}.`);
70
+ excluded = true;
71
+ }
72
+ }
73
+ if (required?.hostVersion !== undefined) {
74
+ if (context.hostVersion === undefined)
75
+ conditions.push(`Host version must satisfy ${required.hostVersion}.`);
76
+ else if (!semver.satisfies(context.hostVersion, required.hostVersion)) {
77
+ reasons.push(`${implementation.id} requires host version ${required.hostVersion}.`);
78
+ excluded = true;
79
+ }
80
+ }
81
+ if (!excluded)
82
+ candidates.push({ implementation, conditions });
83
+ }
84
+ if (candidates.length > 1)
85
+ return {
86
+ status: "ambiguous",
87
+ implementationIds: candidates.map(({ implementation }) => implementation.id),
88
+ };
89
+ const candidate = candidates[0];
90
+ if (candidate === undefined)
91
+ return {
92
+ status: "unsupported",
93
+ reasons: reasons.length > 0
94
+ ? reasons
95
+ : [`No implementation declares the ${agentId} native protocol.`],
96
+ };
97
+ return { status: candidate.conditions.length === 0 ? "selected" : "conditional", ...candidate };
98
+ };
99
+ //# sourceMappingURL=resolution.js.map
@@ -0,0 +1,24 @@
1
+ import * as Schema from "effect/Schema";
2
+ /** Digest of the exact downloaded artifact bytes, independent of the unpacked tree. */
3
+ export declare const ArtifactDigestSchema: Schema.brand<Schema.String, "ArtifactDigest">;
4
+ export type ArtifactDigest = typeof ArtifactDigestSchema.Type;
5
+ /** A relative file in a downloaded package, never a filesystem escape. */
6
+ export declare const ArtifactPathSchema: Schema.NonEmptyString;
7
+ export declare const ArtifactUrlSchema: Schema.URLFromString;
8
+ /** Accepted download inputs; replay verifies each exact artifact without re-reading discovery. */
9
+ export declare const HttpArtifactSnapshotSchema: Schema.Union<readonly [Schema.Struct<{
10
+ readonly format: Schema.Literals<readonly ["skill-md", "zip", "tar", "tar.gz"]>;
11
+ readonly url: Schema.URLFromString;
12
+ readonly digest: Schema.brand<Schema.String, "ArtifactDigest">;
13
+ }>, Schema.Struct<{
14
+ readonly format: Schema.Literal<"files">;
15
+ readonly files: Schema.$Array<Schema.Struct<{
16
+ readonly path: Schema.NonEmptyString;
17
+ readonly url: Schema.URLFromString;
18
+ readonly digest: Schema.brand<Schema.String, "ArtifactDigest">;
19
+ }>>;
20
+ }>]>;
21
+ export type HttpArtifactSnapshot = typeof HttpArtifactSnapshotSchema.Type;
22
+ /** Recognizable public artifact and discovery locations, leaving clone URLs to Git. */
23
+ export declare const httpSourceKind: (url: URL) => "skill-md" | "archive" | "index" | undefined;
24
+ //# sourceMappingURL=http-artifact.d.ts.map
@@ -0,0 +1,46 @@
1
+ import * as Schema from "effect/Schema";
2
+ /** Digest of the exact downloaded artifact bytes, independent of the unpacked tree. */
3
+ export const ArtifactDigestSchema = Schema.String.pipe(Schema.check(Schema.makeFilter((value) => /^sha256:[0-9a-f]{64}$/u.test(value)
4
+ ? undefined
5
+ : "Expected SHA-256 artifact digest in sha256:<hex> form")), Schema.brand("ArtifactDigest"));
6
+ /** A relative file in a downloaded package, never a filesystem escape. */
7
+ export const ArtifactPathSchema = Schema.NonEmptyString.pipe(Schema.check(Schema.makeFilter((value) => value.includes("\\") ||
8
+ value.includes("\0") ||
9
+ value.startsWith("/") ||
10
+ /^[A-Za-z]:/u.test(value) ||
11
+ value.split("/").some((part) => part === ".." || part === "." || part.length === 0)
12
+ ? "Expected a contained artifact file path"
13
+ : undefined)));
14
+ export const ArtifactUrlSchema = Schema.URLFromString.pipe(Schema.check(Schema.makeFilter((url) => url.protocol === "https:" && url.username === "" && url.password === ""
15
+ ? undefined
16
+ : "Expected a credential-free HTTPS artifact URL")));
17
+ /** Accepted download inputs; replay verifies each exact artifact without re-reading discovery. */
18
+ export const HttpArtifactSnapshotSchema = Schema.Union([
19
+ Schema.Struct({
20
+ format: Schema.Literals(["skill-md", "zip", "tar", "tar.gz"]),
21
+ url: ArtifactUrlSchema,
22
+ digest: ArtifactDigestSchema,
23
+ }),
24
+ Schema.Struct({
25
+ format: Schema.Literal("files"),
26
+ files: Schema.Array(Schema.Struct({
27
+ path: ArtifactPathSchema,
28
+ url: ArtifactUrlSchema,
29
+ digest: ArtifactDigestSchema,
30
+ })).pipe(Schema.check(Schema.isMinLength(1))),
31
+ }),
32
+ ]);
33
+ /** Recognizable public artifact and discovery locations, leaving clone URLs to Git. */
34
+ export const httpSourceKind = (url) => {
35
+ if (url.protocol !== "https:")
36
+ return undefined;
37
+ if (url.pathname.endsWith("/SKILL.md"))
38
+ return "skill-md";
39
+ if (/\.(zip|tar|tar\.gz|tgz)$/iu.test(url.pathname))
40
+ return "archive";
41
+ if (url.pathname === "/" ||
42
+ /^\/\.well-known\/(agent-skills|skills)(?:\/index\.json|\/?)$/u.test(url.pathname))
43
+ return "index";
44
+ return undefined;
45
+ };
46
+ //# sourceMappingURL=http-artifact.js.map
@@ -21,6 +21,12 @@ const printLocalSource = (source) => {
21
21
  */
22
22
  export const printSourceParams = (source) => {
23
23
  switch (source.type) {
24
+ case "http": {
25
+ const url = new URL(source.url.href);
26
+ if (source.entry !== undefined)
27
+ url.hash = `skill=${encodeURIComponent(source.entry)}`;
28
+ return url.href;
29
+ }
24
30
  case "local":
25
31
  return printLocalSource(source);
26
32
  case "git": {
@@ -28,7 +34,14 @@ export const printSourceParams = (source) => {
28
34
  onSome: printForgeCoordinate,
29
35
  onNone: () => {
30
36
  const url = new URL(source.url.href);
31
- url.hash = Option.getOrElse(source.ref, () => "");
37
+ if (Option.isSome(source.subPath)) {
38
+ const selector = new URLSearchParams({ path: source.subPath.value });
39
+ if (Option.isSome(source.ref))
40
+ selector.set("ref", source.ref.value);
41
+ url.hash = `axm:${selector.toString()}`;
42
+ }
43
+ else
44
+ url.hash = Option.getOrElse(source.ref, () => "");
32
45
  return url.href;
33
46
  },
34
47
  });
@@ -142,6 +142,9 @@ export interface NamedRegistryCandidate {
142
142
  export interface ExtensionFiles {
143
143
  /** Absolute path to directory containing extension files. */
144
144
  readonly directory: string;
145
+ /** Complete package context for a selected component. */
146
+ readonly packageDirectory?: string;
147
+ readonly componentPath?: string;
145
148
  }
146
149
  /**
147
150
  * Source host provider that unifies how all source types are accessed.