@enactprotocol/shared 2.2.4 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -18
- package/dist/config.d.ts +12 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +32 -6
- package/dist/config.js.map +1 -1
- package/dist/execution/action-command.d.ts +131 -0
- package/dist/execution/action-command.d.ts.map +1 -0
- package/dist/execution/action-command.js +300 -0
- package/dist/execution/action-command.js.map +1 -0
- package/dist/execution/command.d.ts +8 -8
- package/dist/execution/command.js +6 -6
- package/dist/execution/index.d.ts +1 -0
- package/dist/execution/index.d.ts.map +1 -1
- package/dist/execution/index.js +2 -0
- package/dist/execution/index.js.map +1 -1
- package/dist/execution/types.d.ts +5 -2
- package/dist/execution/types.d.ts.map +1 -1
- package/dist/execution/types.js.map +1 -1
- package/dist/index.d.ts +8 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -4
- package/dist/index.js.map +1 -1
- package/dist/manifest/actions-loader.d.ts +29 -0
- package/dist/manifest/actions-loader.d.ts.map +1 -0
- package/dist/manifest/actions-loader.js +34 -0
- package/dist/manifest/actions-loader.js.map +1 -0
- package/dist/manifest/actions-parser.d.ts +69 -0
- package/dist/manifest/actions-parser.d.ts.map +1 -0
- package/dist/manifest/actions-parser.js +265 -0
- package/dist/manifest/actions-parser.js.map +1 -0
- package/dist/manifest/index.d.ts +2 -0
- package/dist/manifest/index.d.ts.map +1 -1
- package/dist/manifest/index.js +4 -0
- package/dist/manifest/index.js.map +1 -1
- package/dist/manifest/loader.d.ts +7 -2
- package/dist/manifest/loader.d.ts.map +1 -1
- package/dist/manifest/loader.js +71 -4
- package/dist/manifest/loader.js.map +1 -1
- package/dist/manifest/parser.d.ts +1 -0
- package/dist/manifest/parser.d.ts.map +1 -1
- package/dist/manifest/parser.js +1 -0
- package/dist/manifest/parser.js.map +1 -1
- package/dist/manifest/scripts.d.ts +19 -0
- package/dist/manifest/scripts.d.ts.map +1 -0
- package/dist/manifest/scripts.js +102 -0
- package/dist/manifest/scripts.js.map +1 -0
- package/dist/manifest/validator.d.ts +1 -8
- package/dist/manifest/validator.d.ts.map +1 -1
- package/dist/manifest/validator.js +14 -13
- package/dist/manifest/validator.js.map +1 -1
- package/dist/mcp-registry.js +5 -5
- package/dist/mcp-registry.js.map +1 -1
- package/dist/paths.d.ts +9 -2
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +12 -3
- package/dist/paths.js.map +1 -1
- package/dist/registry.d.ts +3 -2
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +5 -5
- package/dist/registry.js.map +1 -1
- package/dist/resolver.d.ts +55 -4
- package/dist/resolver.d.ts.map +1 -1
- package/dist/resolver.js +133 -75
- package/dist/resolver.js.map +1 -1
- package/dist/types/actions.d.ts +194 -0
- package/dist/types/actions.d.ts.map +1 -0
- package/dist/types/actions.js +32 -0
- package/dist/types/actions.js.map +1 -0
- package/dist/types/index.d.ts +3 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/manifest.d.ts +50 -5
- package/dist/types/manifest.d.ts.map +1 -1
- package/dist/types/manifest.js +10 -2
- package/dist/types/manifest.js.map +1 -1
- package/package.json +2 -2
- package/src/config.ts +48 -6
- package/src/execution/action-command.ts +417 -0
- package/src/execution/command.ts +8 -8
- package/src/execution/index.ts +17 -0
- package/src/execution/types.ts +13 -2
- package/src/index.ts +37 -0
- package/src/manifest/actions-loader.ts +49 -0
- package/src/manifest/index.ts +12 -0
- package/src/manifest/loader.ts +77 -4
- package/src/manifest/parser.ts +1 -0
- package/src/manifest/scripts.ts +116 -0
- package/src/manifest/validator.ts +15 -14
- package/src/mcp-registry.ts +5 -5
- package/src/paths.ts +13 -3
- package/src/registry.ts +5 -5
- package/src/resolver.ts +172 -77
- package/src/types/actions.ts +223 -0
- package/src/types/index.ts +11 -0
- package/src/types/manifest.ts +67 -6
- package/tests/action-command.test.ts +249 -0
- package/tests/config-normalization.test.ts +279 -0
- package/tests/config.test.ts +4 -1
- package/tests/effective-input-schema.test.ts +86 -0
- package/tests/fixtures/valid-tool.md +5 -12
- package/tests/fixtures/valid-tool.yaml +3 -10
- package/tests/hooks.test.ts +177 -0
- package/tests/manifest/loader.test.ts +34 -20
- package/tests/manifest/parser.test.ts +11 -15
- package/tests/manifest/validator.test.ts +7 -17
- package/tests/manifest-types.test.ts +9 -11
- package/tests/paths.test.ts +11 -4
- package/tests/registry.test.ts +12 -11
- package/tests/resolver.test.ts +11 -7
- package/tsconfig.tsbuildinfo +1 -1
package/dist/types/manifest.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* TypeScript types for Enact tool manifests
|
|
3
|
-
* These types define the structure of SKILL.md (and legacy enact.yaml/enact.md) frontmatter
|
|
3
|
+
* These types define the structure of SKILL.md (and skill.yaml/legacy enact.yaml/enact.md) frontmatter
|
|
4
4
|
*/
|
|
5
5
|
import type { JSONSchema7 } from "json-schema";
|
|
6
6
|
/**
|
|
@@ -11,6 +11,8 @@ export interface EnvVariable {
|
|
|
11
11
|
description: string;
|
|
12
12
|
/** If true, stored in OS keyring; if false, stored in .env files */
|
|
13
13
|
secret?: boolean;
|
|
14
|
+
/** If true, must be set before execution (no default fallback) */
|
|
15
|
+
required?: boolean;
|
|
14
16
|
/** Default value if not set (only for non-secrets) */
|
|
15
17
|
default?: string;
|
|
16
18
|
}
|
|
@@ -44,6 +46,28 @@ export interface ToolAnnotations {
|
|
|
44
46
|
/** Tool interacts with external systems (network, APIs) */
|
|
45
47
|
openWorldHint?: boolean;
|
|
46
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* Lifecycle hooks for tool installation and management
|
|
51
|
+
*/
|
|
52
|
+
export interface ToolHooks {
|
|
53
|
+
/** Command(s) to run after the tool is installed/extracted (e.g., "npm install", "pip install -r requirements.txt") */
|
|
54
|
+
postinstall?: string | string[];
|
|
55
|
+
/** Build command(s) to run before execution (e.g., "pip install -r requirements.txt") */
|
|
56
|
+
build?: string | string[];
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Script definition — either a simple command string or an expanded object
|
|
60
|
+
*
|
|
61
|
+
* Simple form: "python main.py {{url}}"
|
|
62
|
+
* Expanded form: { command: "python main.py {{url}}", description: "Scrape a URL" }
|
|
63
|
+
*/
|
|
64
|
+
export type ScriptDefinition = string | {
|
|
65
|
+
command: string;
|
|
66
|
+
description?: string;
|
|
67
|
+
inputSchema?: JSONSchema7;
|
|
68
|
+
outputSchema?: JSONSchema7;
|
|
69
|
+
annotations?: ToolAnnotations;
|
|
70
|
+
};
|
|
47
71
|
/**
|
|
48
72
|
* Resource requirements for tool execution
|
|
49
73
|
*/
|
|
@@ -68,7 +92,7 @@ export interface ToolExample {
|
|
|
68
92
|
}
|
|
69
93
|
/**
|
|
70
94
|
* Complete tool manifest structure
|
|
71
|
-
* This represents the YAML frontmatter in SKILL.md (or legacy enact.md/enact.yaml)
|
|
95
|
+
* This represents the YAML frontmatter in SKILL.md (or skill.yaml/legacy enact.md/enact.yaml)
|
|
72
96
|
*/
|
|
73
97
|
export interface ToolManifest {
|
|
74
98
|
/** Hierarchical tool identifier (e.g., "org/category/tool-name") */
|
|
@@ -91,8 +115,6 @@ export interface ToolManifest {
|
|
|
91
115
|
license?: string;
|
|
92
116
|
/** Keywords for tool discovery and categorization */
|
|
93
117
|
tags?: string[];
|
|
94
|
-
/** JSON Schema defining input parameters */
|
|
95
|
-
inputSchema?: JSONSchema7;
|
|
96
118
|
/** JSON Schema defining output structure */
|
|
97
119
|
outputSchema?: JSONSchema7;
|
|
98
120
|
/** Environment variables and secrets required by the tool */
|
|
@@ -101,6 +123,22 @@ export interface ToolManifest {
|
|
|
101
123
|
annotations?: ToolAnnotations;
|
|
102
124
|
/** Resource limits and requirements */
|
|
103
125
|
resources?: ResourceRequirements;
|
|
126
|
+
/** Lifecycle hooks (e.g., postinstall build step) */
|
|
127
|
+
hooks?: ToolHooks;
|
|
128
|
+
/**
|
|
129
|
+
* Inline executable scripts (each becomes an MCP tool via colon syntax)
|
|
130
|
+
*
|
|
131
|
+
* Scripts replace the need for a separate ACTIONS.yaml file.
|
|
132
|
+
* Each script maps a name to a command with {{param}} template syntax.
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* scripts:
|
|
136
|
+
* scrape: python scripts/scrape.py {{url}}
|
|
137
|
+
* crawl:
|
|
138
|
+
* command: python scripts/crawl.py {{url}} {{depth}}
|
|
139
|
+
* description: Crawl a website to specified depth
|
|
140
|
+
*/
|
|
141
|
+
scripts?: Record<string, ScriptDefinition>;
|
|
104
142
|
/** Environment requirements (intended product, system packages, network access, etc.) */
|
|
105
143
|
compatibility?: string;
|
|
106
144
|
/** Arbitrary key-value metadata for additional properties */
|
|
@@ -194,13 +232,20 @@ export interface ToolResolution {
|
|
|
194
232
|
manifestPath: string;
|
|
195
233
|
/** Tool version (if available) */
|
|
196
234
|
version?: string | undefined;
|
|
235
|
+
/** The resolved script (if a script was specified via colon syntax) */
|
|
236
|
+
action?: import("./actions").Action | undefined;
|
|
237
|
+
/** The requested script name (if specified via colon syntax) */
|
|
238
|
+
actionName?: string | undefined;
|
|
239
|
+
/** The scripts manifest (converted from inline scripts) */
|
|
240
|
+
actionsManifest?: import("./actions").ActionsManifest | undefined;
|
|
197
241
|
}
|
|
198
242
|
/**
|
|
199
243
|
* Supported manifest file names
|
|
200
244
|
* SKILL.md is the primary format (aligned with Anthropic Agent Skills)
|
|
245
|
+
* skill.yaml/yml is the package manifest
|
|
201
246
|
* enact.md/yaml/yml are supported for backwards compatibility
|
|
202
247
|
*/
|
|
203
|
-
export declare const MANIFEST_FILES: readonly ["SKILL.md", "enact.md", "enact.yaml", "enact.yml"];
|
|
248
|
+
export declare const MANIFEST_FILES: readonly ["SKILL.md", "skill.yaml", "skill.yml", "enact.md", "enact.yaml", "enact.yml"];
|
|
204
249
|
export type ManifestFileName = (typeof MANIFEST_FILES)[number];
|
|
205
250
|
/**
|
|
206
251
|
* Package manifest file name
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/types/manifest.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,8DAA8D;IAC9D,WAAW,EAAE,MAAM,CAAC;IACpB,oEAAoE;IACpE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,sDAAsD;IACtD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;AAEvD;;GAEG;AACH,MAAM,WAAW,MAAM;IACrB,kBAAkB;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,8BAA8B;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oCAAoC;IACpC,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,kCAAkC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2CAA2C;IAC3C,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,yCAAyC;IACzC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,kDAAkD;IAClD,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,2DAA2D;IAC3D,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,kDAAkD;IAClD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uCAAuC;IACvC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,wCAAwC;IACxC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,wCAAwC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,uCAAuC;IACvC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,oCAAoC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAG3B,oEAAoE;IACpE,IAAI,EAAE,MAAM,CAAC;IAEb,uDAAuD;IACvD,WAAW,EAAE,MAAM,CAAC;IAIpB,kEAAkE;IAClE,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,oDAAoD;IACpD,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,uEAAuE;IACvE,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,kEAAkE;IAClE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAE1B,8DAA8D;IAC9D,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,uDAAuD;IACvD,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,0DAA0D;IAC1D,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,qDAAqD;IACrD,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAIhB,4CAA4C;IAC5C,
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/types/manifest.ts"],"names":[],"mappings":"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"}
|
package/dist/types/manifest.js
CHANGED
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* TypeScript types for Enact tool manifests
|
|
3
|
-
* These types define the structure of SKILL.md (and legacy enact.yaml/enact.md) frontmatter
|
|
3
|
+
* These types define the structure of SKILL.md (and skill.yaml/legacy enact.yaml/enact.md) frontmatter
|
|
4
4
|
*/
|
|
5
5
|
/**
|
|
6
6
|
* Supported manifest file names
|
|
7
7
|
* SKILL.md is the primary format (aligned with Anthropic Agent Skills)
|
|
8
|
+
* skill.yaml/yml is the package manifest
|
|
8
9
|
* enact.md/yaml/yml are supported for backwards compatibility
|
|
9
10
|
*/
|
|
10
|
-
export const MANIFEST_FILES = [
|
|
11
|
+
export const MANIFEST_FILES = [
|
|
12
|
+
"SKILL.md",
|
|
13
|
+
"skill.yaml",
|
|
14
|
+
"skill.yml",
|
|
15
|
+
"enact.md",
|
|
16
|
+
"enact.yaml",
|
|
17
|
+
"enact.yml",
|
|
18
|
+
];
|
|
11
19
|
/**
|
|
12
20
|
* Package manifest file name
|
|
13
21
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/types/manifest.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/types/manifest.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAkTH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,UAAU;IACV,YAAY;IACZ,WAAW;IACX,UAAU;IACV,YAAY;IACZ,WAAW;CACH,CAAC;AAGX;;GAEG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,oBAAoB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@enactprotocol/shared",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.1",
|
|
4
4
|
"description": "Core business logic and utilities for Enact",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"typecheck": "tsc --noEmit"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@enactprotocol/trust": "2.
|
|
21
|
+
"@enactprotocol/trust": "2.3.1",
|
|
22
22
|
"js-yaml": "^4.1.1",
|
|
23
23
|
"zod": "^4.1.13"
|
|
24
24
|
},
|
package/src/config.ts
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
7
|
-
import { dirname
|
|
7
|
+
import { dirname } from "node:path";
|
|
8
8
|
import yaml from "js-yaml";
|
|
9
|
-
import { getConfigPath, getEnactHome } from "./paths";
|
|
9
|
+
import { getConfigPath, getEnactHome, getSkillsDir } from "./paths";
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Trust configuration for attestation verification
|
|
@@ -26,6 +26,10 @@ export interface TrustConfig {
|
|
|
26
26
|
policy?: "require_attestation" | "prompt" | "allow";
|
|
27
27
|
/** Minimum number of trusted attestations required */
|
|
28
28
|
minimum_attestations?: number;
|
|
29
|
+
/** Alias: when true, sets policy to 'require_attestation'; when false, sets policy to 'allow' */
|
|
30
|
+
require_signatures?: boolean;
|
|
31
|
+
/** Alias: merged into auditors list */
|
|
32
|
+
trusted_publishers?: string[];
|
|
29
33
|
}
|
|
30
34
|
|
|
31
35
|
/**
|
|
@@ -41,11 +45,20 @@ export interface CacheConfig {
|
|
|
41
45
|
/**
|
|
42
46
|
* Execution configuration
|
|
43
47
|
*/
|
|
48
|
+
/** Execution backend type */
|
|
49
|
+
export type ExecutionBackend = "local" | "docker" | "dagger" | "container" | "remote";
|
|
50
|
+
|
|
44
51
|
export interface ExecutionConfig {
|
|
45
52
|
/** Default timeout for tool execution (e.g., "30s", "5m") */
|
|
46
53
|
defaultTimeout?: string;
|
|
47
54
|
/** Whether to run in verbose mode */
|
|
48
55
|
verbose?: boolean;
|
|
56
|
+
/** Default execution backend */
|
|
57
|
+
default?: ExecutionBackend;
|
|
58
|
+
/** Fallback backend if default is unavailable */
|
|
59
|
+
fallback?: ExecutionBackend;
|
|
60
|
+
/** Package scopes that bypass container isolation and run locally (e.g., ["@my-org/*"]) */
|
|
61
|
+
trusted_scopes?: string[];
|
|
49
62
|
}
|
|
50
63
|
|
|
51
64
|
/**
|
|
@@ -142,6 +155,33 @@ function deepMerge(target: EnactConfig, source: Partial<EnactConfig>): EnactConf
|
|
|
142
155
|
return result;
|
|
143
156
|
}
|
|
144
157
|
|
|
158
|
+
/**
|
|
159
|
+
* Normalize config by resolving alias fields into their canonical counterparts.
|
|
160
|
+
* - trust.require_signatures → trust.policy
|
|
161
|
+
* - trust.trusted_publishers → merged into trust.auditors
|
|
162
|
+
*/
|
|
163
|
+
function normalizeConfig(config: EnactConfig): EnactConfig {
|
|
164
|
+
if (config.trust) {
|
|
165
|
+
// require_signatures is an alias for policy
|
|
166
|
+
if (config.trust.require_signatures !== undefined && config.trust.policy === undefined) {
|
|
167
|
+
config.trust.policy = config.trust.require_signatures ? "require_attestation" : "allow";
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// trusted_publishers merges into auditors
|
|
171
|
+
if (config.trust.trusted_publishers?.length) {
|
|
172
|
+
const auditors = config.trust.auditors ?? [];
|
|
173
|
+
for (const publisher of config.trust.trusted_publishers) {
|
|
174
|
+
if (!auditors.includes(publisher)) {
|
|
175
|
+
auditors.push(publisher);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
config.trust.auditors = auditors;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return config;
|
|
183
|
+
}
|
|
184
|
+
|
|
145
185
|
/**
|
|
146
186
|
* Load configuration from ~/.enact/config.yaml
|
|
147
187
|
* Returns default config if file doesn't exist or is invalid
|
|
@@ -162,8 +202,10 @@ export function loadConfig(): EnactConfig {
|
|
|
162
202
|
return { ...DEFAULT_CONFIG };
|
|
163
203
|
}
|
|
164
204
|
|
|
165
|
-
//
|
|
166
|
-
|
|
205
|
+
// Normalize aliases in user config BEFORE merging with defaults,
|
|
206
|
+
// so require_signatures → policy conversion isn't blocked by default policy
|
|
207
|
+
const normalized = normalizeConfig(parsed as EnactConfig);
|
|
208
|
+
return deepMerge(DEFAULT_CONFIG, normalized);
|
|
167
209
|
} catch {
|
|
168
210
|
// Return defaults on any error (parse error, read error, etc.)
|
|
169
211
|
return { ...DEFAULT_CONFIG };
|
|
@@ -275,7 +317,7 @@ export function configExists(): boolean {
|
|
|
275
317
|
export function ensureGlobalSetup(): boolean {
|
|
276
318
|
const enactHome = getEnactHome();
|
|
277
319
|
const configPath = getConfigPath();
|
|
278
|
-
const cacheDir =
|
|
320
|
+
const cacheDir = getSkillsDir();
|
|
279
321
|
|
|
280
322
|
let performedSetup = false;
|
|
281
323
|
|
|
@@ -285,7 +327,7 @@ export function ensureGlobalSetup(): boolean {
|
|
|
285
327
|
performedSetup = true;
|
|
286
328
|
}
|
|
287
329
|
|
|
288
|
-
// Ensure ~/.
|
|
330
|
+
// Ensure ~/.agent/skills/ directory exists
|
|
289
331
|
if (!existsSync(cacheDir)) {
|
|
290
332
|
mkdirSync(cacheDir, { recursive: true });
|
|
291
333
|
performedSetup = true;
|
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Action command interpolation for Agent Actions
|
|
3
|
+
*
|
|
4
|
+
* Implements the {{param}} template syntax specified in RFC-001-AGENT-ACTIONS.
|
|
5
|
+
*
|
|
6
|
+
* ## Key Differences from ${param} (command.ts)
|
|
7
|
+
*
|
|
8
|
+
* 1. **No shell escaping**: Values are passed directly as arguments to execve()
|
|
9
|
+
* 2. **Array form only**: Templates only work in array-form commands
|
|
10
|
+
* 3. **Argument omission**: Optional params without values are omitted entirely
|
|
11
|
+
* 4. **Single argument substitution**: Each {{var}} becomes exactly one argument
|
|
12
|
+
*
|
|
13
|
+
* ## Security
|
|
14
|
+
*
|
|
15
|
+
* This template system is designed to prevent command injection:
|
|
16
|
+
* - Values are never passed through a shell interpreter
|
|
17
|
+
* - No argument splitting on whitespace or metacharacters
|
|
18
|
+
* - Each template becomes a single argument regardless of content
|
|
19
|
+
*
|
|
20
|
+
* @see RFC-001-AGENT-ACTIONS.md
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import type { JSONSchema7 } from "json-schema";
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Token types for action command parsing
|
|
27
|
+
*/
|
|
28
|
+
export interface ActionCommandLiteralToken {
|
|
29
|
+
type: "literal";
|
|
30
|
+
value: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface ActionCommandParamToken {
|
|
34
|
+
type: "parameter";
|
|
35
|
+
name: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export type ActionCommandToken = ActionCommandLiteralToken | ActionCommandParamToken;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Parsed representation of a single command argument
|
|
42
|
+
*/
|
|
43
|
+
export interface ParsedArgument {
|
|
44
|
+
/** The tokens that make up this argument */
|
|
45
|
+
tokens: ActionCommandToken[];
|
|
46
|
+
/** Parameter names referenced in this argument */
|
|
47
|
+
parameters: string[];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Result of parsing an action command
|
|
52
|
+
*/
|
|
53
|
+
export interface ParsedActionCommand {
|
|
54
|
+
/** Original command (array form) */
|
|
55
|
+
original: string[];
|
|
56
|
+
/** Parsed arguments with tokens */
|
|
57
|
+
arguments: ParsedArgument[];
|
|
58
|
+
/** All unique parameter names across all arguments */
|
|
59
|
+
allParameters: string[];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Regex to match {{param}} template syntax
|
|
64
|
+
*/
|
|
65
|
+
const ACTION_TEMPLATE_REGEX = /\{\{([^}]+)\}\}/g;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Check if a string contains {{param}} templates
|
|
69
|
+
*/
|
|
70
|
+
export function hasActionTemplates(str: string): boolean {
|
|
71
|
+
// Reset regex state and test
|
|
72
|
+
ACTION_TEMPLATE_REGEX.lastIndex = 0;
|
|
73
|
+
return ACTION_TEMPLATE_REGEX.test(str);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Parse a single argument string into tokens
|
|
78
|
+
*
|
|
79
|
+
* @param arg - The argument string to parse
|
|
80
|
+
* @returns ParsedArgument with tokens and parameter names
|
|
81
|
+
*/
|
|
82
|
+
export function parseActionArgument(arg: string): ParsedArgument {
|
|
83
|
+
const tokens: ActionCommandToken[] = [];
|
|
84
|
+
const parameters: string[] = [];
|
|
85
|
+
|
|
86
|
+
let lastIndex = 0;
|
|
87
|
+
const regex = /\{\{([^}]+)\}\}/g;
|
|
88
|
+
let match: RegExpExecArray | null = regex.exec(arg);
|
|
89
|
+
|
|
90
|
+
while (match !== null) {
|
|
91
|
+
// Add literal text before this match
|
|
92
|
+
if (match.index > lastIndex) {
|
|
93
|
+
tokens.push({
|
|
94
|
+
type: "literal",
|
|
95
|
+
value: arg.slice(lastIndex, match.index),
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Add the parameter token
|
|
100
|
+
const paramName = match[1]?.trim();
|
|
101
|
+
if (paramName) {
|
|
102
|
+
tokens.push({
|
|
103
|
+
type: "parameter",
|
|
104
|
+
name: paramName,
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
if (!parameters.includes(paramName)) {
|
|
108
|
+
parameters.push(paramName);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
lastIndex = match.index + match[0].length;
|
|
113
|
+
match = regex.exec(arg);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Add any remaining literal text
|
|
117
|
+
if (lastIndex < arg.length) {
|
|
118
|
+
tokens.push({
|
|
119
|
+
type: "literal",
|
|
120
|
+
value: arg.slice(lastIndex),
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// If no tokens were created, the whole arg is a literal
|
|
125
|
+
if (tokens.length === 0) {
|
|
126
|
+
tokens.push({
|
|
127
|
+
type: "literal",
|
|
128
|
+
value: arg,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return { tokens, parameters };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Parse an action command (array form) into tokens
|
|
137
|
+
*
|
|
138
|
+
* @param command - The command array to parse
|
|
139
|
+
* @returns ParsedActionCommand with all arguments parsed
|
|
140
|
+
*/
|
|
141
|
+
export function parseActionCommand(command: string[]): ParsedActionCommand {
|
|
142
|
+
const parsedArgs: ParsedArgument[] = [];
|
|
143
|
+
const allParameters: string[] = [];
|
|
144
|
+
|
|
145
|
+
for (const arg of command) {
|
|
146
|
+
const parsed = parseActionArgument(arg);
|
|
147
|
+
parsedArgs.push(parsed);
|
|
148
|
+
|
|
149
|
+
// Collect unique parameters
|
|
150
|
+
for (const param of parsed.parameters) {
|
|
151
|
+
if (!allParameters.includes(param)) {
|
|
152
|
+
allParameters.push(param);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return {
|
|
158
|
+
original: command,
|
|
159
|
+
arguments: parsedArgs,
|
|
160
|
+
allParameters,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Options for action command interpolation
|
|
166
|
+
*/
|
|
167
|
+
export interface ActionInterpolationOptions {
|
|
168
|
+
/**
|
|
169
|
+
* JSON Schema for input validation
|
|
170
|
+
* Used to determine which parameters are optional and have defaults
|
|
171
|
+
*/
|
|
172
|
+
inputSchema?: JSONSchema7;
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Whether to omit arguments for optional params with no value
|
|
176
|
+
* Default: true (as per RFC-001)
|
|
177
|
+
*/
|
|
178
|
+
omitMissingOptional?: boolean;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Get the default value for a parameter from the input schema
|
|
183
|
+
*/
|
|
184
|
+
function getDefaultValue(paramName: string, inputSchema?: JSONSchema7): unknown | undefined {
|
|
185
|
+
if (!inputSchema || inputSchema.type !== "object") {
|
|
186
|
+
return undefined;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const properties = inputSchema.properties as Record<string, JSONSchema7> | undefined;
|
|
190
|
+
if (!properties) {
|
|
191
|
+
return undefined;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const propSchema = properties[paramName];
|
|
195
|
+
if (!propSchema || typeof propSchema === "boolean") {
|
|
196
|
+
return undefined;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return propSchema.default;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Check if a parameter is required according to the input schema
|
|
204
|
+
*/
|
|
205
|
+
function isRequired(paramName: string, inputSchema?: JSONSchema7): boolean {
|
|
206
|
+
if (!inputSchema) {
|
|
207
|
+
return true; // Conservative default
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const required = inputSchema.required as string[] | undefined;
|
|
211
|
+
return required?.includes(paramName) ?? false;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Convert a value to string for command argument
|
|
216
|
+
*
|
|
217
|
+
* Unlike command.ts, we don't shell-escape here because values
|
|
218
|
+
* are passed directly to execve(), not through a shell.
|
|
219
|
+
*/
|
|
220
|
+
function valueToArgString(value: unknown): string {
|
|
221
|
+
if (value === null || value === undefined) {
|
|
222
|
+
return "";
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (typeof value === "string") {
|
|
226
|
+
return value;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
230
|
+
return String(value);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (typeof value === "object") {
|
|
234
|
+
return JSON.stringify(value);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return String(value);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Interpolate a single argument with parameter values
|
|
242
|
+
*
|
|
243
|
+
* @param parsed - Parsed argument with tokens
|
|
244
|
+
* @param params - Parameter values
|
|
245
|
+
* @param inputSchema - JSON Schema for defaults and required checks
|
|
246
|
+
* @returns Interpolated string, or undefined if argument should be omitted
|
|
247
|
+
*/
|
|
248
|
+
function interpolateArgument(
|
|
249
|
+
parsed: ParsedArgument,
|
|
250
|
+
params: Record<string, unknown>,
|
|
251
|
+
inputSchema?: JSONSchema7
|
|
252
|
+
): string | undefined {
|
|
253
|
+
// Check if any parameter in this argument should cause omission
|
|
254
|
+
for (const paramName of parsed.parameters) {
|
|
255
|
+
const value = params[paramName];
|
|
256
|
+
const defaultValue = getDefaultValue(paramName, inputSchema);
|
|
257
|
+
const required = isRequired(paramName, inputSchema);
|
|
258
|
+
|
|
259
|
+
// If parameter is not provided
|
|
260
|
+
if (value === undefined) {
|
|
261
|
+
// Use default if available
|
|
262
|
+
if (defaultValue !== undefined) {
|
|
263
|
+
// Continue with default value (handled below in token processing)
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// If optional (not required) and no default, omit entire argument
|
|
268
|
+
if (!required) {
|
|
269
|
+
return undefined;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// If required and no value, this is an error
|
|
273
|
+
throw new Error(`Missing required parameter: ${paramName}`);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Build the interpolated string
|
|
278
|
+
const parts: string[] = [];
|
|
279
|
+
|
|
280
|
+
for (const token of parsed.tokens) {
|
|
281
|
+
if (token.type === "literal") {
|
|
282
|
+
parts.push(token.value);
|
|
283
|
+
} else {
|
|
284
|
+
const paramName = token.name;
|
|
285
|
+
let value = params[paramName];
|
|
286
|
+
|
|
287
|
+
// Apply default if value not provided
|
|
288
|
+
if (value === undefined) {
|
|
289
|
+
value = getDefaultValue(paramName, inputSchema);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
parts.push(valueToArgString(value));
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
return parts.join("");
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Interpolate an action command with parameter values
|
|
301
|
+
*
|
|
302
|
+
* Implements RFC-001 template substitution rules:
|
|
303
|
+
* 1. Each {{var}} is replaced with the literal value as a single argument
|
|
304
|
+
* 2. Optional parameters without values cause the argument to be omitted
|
|
305
|
+
* 3. No shell interpolation - values passed directly to execve()
|
|
306
|
+
*
|
|
307
|
+
* @param command - Array-form command with {{param}} templates
|
|
308
|
+
* @param params - Parameter values
|
|
309
|
+
* @param options - Interpolation options
|
|
310
|
+
* @returns Array of command arguments ready for execve()
|
|
311
|
+
*/
|
|
312
|
+
export function interpolateActionCommand(
|
|
313
|
+
command: string[],
|
|
314
|
+
params: Record<string, unknown>,
|
|
315
|
+
options: ActionInterpolationOptions = {}
|
|
316
|
+
): string[] {
|
|
317
|
+
const { inputSchema, omitMissingOptional = true } = options;
|
|
318
|
+
const parsed = parseActionCommand(command);
|
|
319
|
+
const result: string[] = [];
|
|
320
|
+
|
|
321
|
+
for (const arg of parsed.arguments) {
|
|
322
|
+
// If argument has no parameters, include it as-is
|
|
323
|
+
if (arg.parameters.length === 0) {
|
|
324
|
+
// It's just a literal
|
|
325
|
+
const literal = arg.tokens[0];
|
|
326
|
+
if (literal && literal.type === "literal") {
|
|
327
|
+
result.push(literal.value);
|
|
328
|
+
}
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
const interpolated = interpolateArgument(arg, params, inputSchema);
|
|
332
|
+
|
|
333
|
+
// undefined means omit this argument
|
|
334
|
+
if (interpolated === undefined) {
|
|
335
|
+
if (!omitMissingOptional) {
|
|
336
|
+
// If not omitting, use empty string
|
|
337
|
+
result.push("");
|
|
338
|
+
}
|
|
339
|
+
// Otherwise skip this argument entirely
|
|
340
|
+
continue;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
result.push(interpolated);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
return result;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Validate that all required parameters are provided
|
|
351
|
+
*
|
|
352
|
+
* @param command - Array-form command
|
|
353
|
+
* @param params - Provided parameter values
|
|
354
|
+
* @param inputSchema - JSON Schema for required field info
|
|
355
|
+
* @returns Array of missing required parameter names
|
|
356
|
+
*/
|
|
357
|
+
export function getMissingRequiredParams(
|
|
358
|
+
command: string[],
|
|
359
|
+
params: Record<string, unknown>,
|
|
360
|
+
inputSchema?: JSONSchema7
|
|
361
|
+
): string[] {
|
|
362
|
+
const parsed = parseActionCommand(command);
|
|
363
|
+
const missing: string[] = [];
|
|
364
|
+
|
|
365
|
+
for (const paramName of parsed.allParameters) {
|
|
366
|
+
const value = params[paramName];
|
|
367
|
+
const defaultValue = getDefaultValue(paramName, inputSchema);
|
|
368
|
+
const required = isRequired(paramName, inputSchema);
|
|
369
|
+
|
|
370
|
+
if (required && value === undefined && defaultValue === undefined) {
|
|
371
|
+
missing.push(paramName);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
return missing;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Get all parameters referenced in a command
|
|
380
|
+
*
|
|
381
|
+
* @param command - Array-form command
|
|
382
|
+
* @returns Array of parameter names
|
|
383
|
+
*/
|
|
384
|
+
export function getActionCommandParams(command: string[]): string[] {
|
|
385
|
+
return parseActionCommand(command).allParameters;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Prepare an action command for execution
|
|
390
|
+
*
|
|
391
|
+
* This is the main entry point for preparing action commands.
|
|
392
|
+
* It validates required parameters and interpolates the command.
|
|
393
|
+
*
|
|
394
|
+
* @param command - Array-form command with {{param}} templates
|
|
395
|
+
* @param params - Parameter values
|
|
396
|
+
* @param inputSchema - JSON Schema for validation
|
|
397
|
+
* @returns Array of command arguments ready for execve()
|
|
398
|
+
* @throws Error if required parameters are missing
|
|
399
|
+
*/
|
|
400
|
+
export function prepareActionCommand(
|
|
401
|
+
command: string[],
|
|
402
|
+
params: Record<string, unknown>,
|
|
403
|
+
inputSchema?: JSONSchema7
|
|
404
|
+
): string[] {
|
|
405
|
+
// Validate required parameters
|
|
406
|
+
const missing = getMissingRequiredParams(command, params, inputSchema);
|
|
407
|
+
if (missing.length > 0) {
|
|
408
|
+
throw new Error(`Missing required parameters: ${missing.join(", ")}`);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// Interpolate and return
|
|
412
|
+
const options: ActionInterpolationOptions = {};
|
|
413
|
+
if (inputSchema !== undefined) {
|
|
414
|
+
options.inputSchema = inputSchema;
|
|
415
|
+
}
|
|
416
|
+
return interpolateActionCommand(command, params, options);
|
|
417
|
+
}
|