@enactprotocol/cli 2.1.4 → 2.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/index.d.ts +1 -0
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +1 -0
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/init/index.d.ts.map +1 -1
- package/dist/commands/init/index.js +186 -28
- package/dist/commands/init/index.js.map +1 -1
- package/dist/commands/learn/index.d.ts +12 -0
- package/dist/commands/learn/index.d.ts.map +1 -0
- package/dist/commands/learn/index.js +90 -0
- package/dist/commands/learn/index.js.map +1 -0
- package/dist/commands/run/index.d.ts.map +1 -1
- package/dist/commands/run/index.js +36 -6
- package/dist/commands/run/index.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
- package/src/commands/index.ts +1 -0
- package/src/commands/init/index.ts +186 -28
- package/src/commands/learn/index.ts +107 -0
- package/src/commands/run/index.ts +39 -5
- package/src/index.ts +4 -2
- package/tests/commands/init.test.ts +4 -3
- package/tests/commands/learn.test.ts +231 -0
- package/tests/commands/run.test.ts +70 -1
- package/tsconfig.tsbuildinfo +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;GAKG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,sBAAsB,EACtB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,EACpB,uBAAuB,EACvB,uBAAuB,EACvB,oBAAoB,EACpB,uBAAuB,EACvB,sBAAsB,EACtB,mBAAmB,EACnB,sBAAsB,EACtB,qBAAqB,EACrB,oBAAoB,EACpB,qBAAqB,EACrB,sBAAsB,EACtB,oBAAoB,GACrB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE7C,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC;AAK/B,uBAAuB;AACvB,KAAK,UAAU,IAAI;IACjB,+CAA+C;IAC/C,iBAAiB,EAAE,CAAC;IAEpB,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAE9B,OAAO;SACJ,IAAI,CAAC,OAAO,CAAC;SACb,WAAW,CAAC,6DAA6D,CAAC;SAC1E,OAAO,CAAC,OAAO,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@enactprotocol/cli",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.6",
|
|
4
4
|
"description": "Command-line interface for Enact - the npm for AI tools",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -34,10 +34,10 @@
|
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@clack/prompts": "^0.11.0",
|
|
37
|
-
"@enactprotocol/api": "2.1.
|
|
38
|
-
"@enactprotocol/execution": "2.1.
|
|
39
|
-
"@enactprotocol/secrets": "2.1.
|
|
40
|
-
"@enactprotocol/shared": "2.1.
|
|
37
|
+
"@enactprotocol/api": "2.1.6",
|
|
38
|
+
"@enactprotocol/execution": "2.1.6",
|
|
39
|
+
"@enactprotocol/secrets": "2.1.6",
|
|
40
|
+
"@enactprotocol/shared": "2.1.6",
|
|
41
41
|
"commander": "^12.1.0",
|
|
42
42
|
"picocolors": "^1.1.1"
|
|
43
43
|
},
|
package/src/commands/index.ts
CHANGED
|
@@ -17,6 +17,7 @@ export { configureConfigCommand } from "./config";
|
|
|
17
17
|
// Registry commands (Phase 8)
|
|
18
18
|
export { configureSearchCommand } from "./search";
|
|
19
19
|
export { configureGetCommand } from "./get";
|
|
20
|
+
export { configureLearnCommand } from "./learn";
|
|
20
21
|
export { configurePublishCommand } from "./publish";
|
|
21
22
|
export { configureAuthCommand } from "./auth";
|
|
22
23
|
export { configureCacheCommand } from "./cache";
|
|
@@ -72,62 +72,220 @@ Edit this file to create your own tool:
|
|
|
72
72
|
- [Tool Manifest Reference](https://enact.dev/docs/manifest)
|
|
73
73
|
`,
|
|
74
74
|
|
|
75
|
-
"tool-agents.md": `#
|
|
75
|
+
"tool-agents.md": `# Enact Tool Development Guide
|
|
76
76
|
|
|
77
|
-
Enact
|
|
77
|
+
Enact tools are containerized, cryptographically-signed executables. Each tool is defined by an \`enact.md\` file (YAML frontmatter + Markdown docs).
|
|
78
78
|
|
|
79
|
-
##
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
79
|
+
## Quick Reference
|
|
80
|
+
|
|
81
|
+
| Task | Command |
|
|
82
|
+
|------|---------|
|
|
83
|
+
| Run with JSON | \`enact run ./ --args '{"key": "value"}'\` |
|
|
84
|
+
| Run from file | \`enact run ./ --input-file inputs.json\` |
|
|
85
|
+
| Dry run | \`enact run ./ --args '{}' --dry-run\` |
|
|
86
|
+
| Sign & publish | \`enact sign ./ && enact publish ./\` |
|
|
85
87
|
|
|
86
88
|
## enact.md Structure
|
|
89
|
+
|
|
87
90
|
\`\`\`yaml
|
|
88
91
|
---
|
|
89
|
-
name: {{TOOL_NAME}}
|
|
90
|
-
description: What
|
|
91
|
-
version: 1.0.0
|
|
92
|
-
|
|
93
|
-
|
|
92
|
+
name: {{TOOL_NAME}}
|
|
93
|
+
description: What the tool does
|
|
94
|
+
version: 1.0.0
|
|
95
|
+
enact: "2.0.0"
|
|
96
|
+
|
|
97
|
+
from: python:3.12-slim # Docker image (pin versions, not :latest)
|
|
98
|
+
build: pip install requests # Build steps (cached by Dagger)
|
|
94
99
|
command: python /work/main.py \${input}
|
|
95
100
|
timeout: 30s
|
|
101
|
+
|
|
96
102
|
inputSchema:
|
|
97
103
|
type: object
|
|
98
104
|
properties:
|
|
99
|
-
input:
|
|
105
|
+
input:
|
|
106
|
+
type: string
|
|
107
|
+
description: "Input to process"
|
|
100
108
|
required: [input]
|
|
109
|
+
|
|
110
|
+
outputSchema:
|
|
111
|
+
type: object
|
|
112
|
+
properties:
|
|
113
|
+
result:
|
|
114
|
+
type: string
|
|
115
|
+
|
|
101
116
|
env:
|
|
102
|
-
API_KEY:
|
|
117
|
+
API_KEY:
|
|
118
|
+
description: "External API key"
|
|
119
|
+
secret: true # Set via: enact env set API_KEY --secret
|
|
103
120
|
---
|
|
104
121
|
# Tool Name
|
|
105
|
-
Documentation here
|
|
122
|
+
Documentation here.
|
|
106
123
|
\`\`\`
|
|
107
124
|
|
|
125
|
+
## Field Reference
|
|
126
|
+
|
|
127
|
+
| Field | Description |
|
|
128
|
+
|-------|-------------|
|
|
129
|
+
| \`name\` | Hierarchical ID: \`org/category/tool\` |
|
|
130
|
+
| \`description\` | What the tool does |
|
|
131
|
+
| \`version\` | Semver version |
|
|
132
|
+
| \`from\` | Docker image |
|
|
133
|
+
| \`build\` | Build commands (string or array, cached) |
|
|
134
|
+
| \`command\` | Shell command with \`\${param}\` substitution |
|
|
135
|
+
| \`timeout\` | Max execution time (e.g., "30s", "5m") |
|
|
136
|
+
| \`inputSchema\` | JSON Schema for inputs |
|
|
137
|
+
| \`outputSchema\` | JSON Schema for outputs |
|
|
138
|
+
| \`env\` | Environment variables and secrets |
|
|
139
|
+
|
|
108
140
|
## Parameter Substitution
|
|
141
|
+
|
|
142
|
+
Enact auto-quotes parameters. **Never manually quote:**
|
|
143
|
+
|
|
144
|
+
\`\`\`yaml
|
|
145
|
+
# WRONG - causes double-quoting
|
|
146
|
+
command: python /work/main.py "\${input}"
|
|
147
|
+
|
|
148
|
+
# RIGHT - Enact handles quoting
|
|
149
|
+
command: python /work/main.py \${input}
|
|
150
|
+
\`\`\`
|
|
151
|
+
|
|
152
|
+
**Optional params:** Missing optional params become empty strings. Always provide defaults:
|
|
153
|
+
\`\`\`yaml
|
|
154
|
+
inputSchema:
|
|
155
|
+
properties:
|
|
156
|
+
greeting:
|
|
157
|
+
type: string
|
|
158
|
+
default: "Hello" # Recommended for optional params
|
|
159
|
+
\`\`\`
|
|
160
|
+
|
|
161
|
+
Or handle empty in shell:
|
|
162
|
+
\`\`\`yaml
|
|
163
|
+
command: "echo \${greeting:-Hello} \${name}"
|
|
164
|
+
\`\`\`
|
|
165
|
+
|
|
166
|
+
Modifiers:
|
|
109
167
|
- \`\${param}\` — auto-quoted (handles spaces, JSON, special chars)
|
|
110
|
-
- \`\${param:raw}\` —
|
|
111
|
-
- **Never manually quote**: \`"\${param}"\` causes double-quoting
|
|
168
|
+
- \`\${param:raw}\` — raw, no quoting (use carefully)
|
|
112
169
|
|
|
113
170
|
## Output
|
|
114
|
-
|
|
171
|
+
|
|
172
|
+
Output valid JSON to stdout when \`outputSchema\` is defined:
|
|
173
|
+
|
|
115
174
|
\`\`\`python
|
|
116
175
|
import json, sys
|
|
117
|
-
|
|
118
|
-
|
|
176
|
+
|
|
177
|
+
try:
|
|
178
|
+
result = do_work()
|
|
179
|
+
print(json.dumps({"status": "success", "result": result}))
|
|
180
|
+
except Exception as e:
|
|
181
|
+
print(json.dumps({"status": "error", "message": str(e)}))
|
|
182
|
+
sys.exit(1) # non-zero = error
|
|
119
183
|
\`\`\`
|
|
120
184
|
|
|
121
|
-
##
|
|
122
|
-
|
|
185
|
+
## Build Steps by Language
|
|
186
|
+
|
|
187
|
+
**Python:**
|
|
188
|
+
\`\`\`yaml
|
|
189
|
+
from: python:3.12-slim
|
|
190
|
+
build: pip install requests pandas
|
|
191
|
+
\`\`\`
|
|
192
|
+
|
|
193
|
+
**Node.js:**
|
|
194
|
+
\`\`\`yaml
|
|
195
|
+
from: node:20-alpine
|
|
196
|
+
build:
|
|
197
|
+
- npm install
|
|
198
|
+
- npm run build
|
|
199
|
+
\`\`\`
|
|
200
|
+
|
|
201
|
+
**Rust:**
|
|
202
|
+
\`\`\`yaml
|
|
203
|
+
from: rust:1.83-slim
|
|
204
|
+
build: rustc /work/main.rs -o /work/tool
|
|
205
|
+
command: /work/tool \${input}
|
|
206
|
+
\`\`\`
|
|
123
207
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
208
|
+
**Go:**
|
|
209
|
+
\`\`\`yaml
|
|
210
|
+
from: golang:1.22-alpine
|
|
211
|
+
build: cd /work && go build -o tool main.go
|
|
212
|
+
command: /work/tool \${input}
|
|
213
|
+
\`\`\`
|
|
214
|
+
|
|
215
|
+
**System packages:**
|
|
216
|
+
\`\`\`yaml
|
|
217
|
+
build: apt-get update && apt-get install -y libfoo-dev
|
|
218
|
+
\`\`\`
|
|
129
219
|
|
|
130
220
|
Build steps are cached — first run slow, subsequent runs instant.
|
|
221
|
+
|
|
222
|
+
## File Access
|
|
223
|
+
|
|
224
|
+
Tools run in a container with \`/work\` as the working directory. All source files are copied there.
|
|
225
|
+
|
|
226
|
+
## Secrets
|
|
227
|
+
|
|
228
|
+
Declare in \`enact.md\`:
|
|
229
|
+
\`\`\`yaml
|
|
230
|
+
env:
|
|
231
|
+
API_KEY:
|
|
232
|
+
description: "API key for service"
|
|
233
|
+
secret: true
|
|
234
|
+
\`\`\`
|
|
235
|
+
|
|
236
|
+
Set before running:
|
|
237
|
+
\`\`\`bash
|
|
238
|
+
enact env set API_KEY --secret --namespace {{TOOL_NAME}}
|
|
239
|
+
\`\`\`
|
|
240
|
+
|
|
241
|
+
Access in code:
|
|
242
|
+
\`\`\`python
|
|
243
|
+
import os
|
|
244
|
+
api_key = os.environ.get('API_KEY')
|
|
245
|
+
\`\`\`
|
|
246
|
+
|
|
247
|
+
## LLM Instruction Tools
|
|
248
|
+
|
|
249
|
+
Tools without a \`command\` field are interpreted by LLMs:
|
|
250
|
+
|
|
251
|
+
\`\`\`yaml
|
|
252
|
+
---
|
|
253
|
+
name: myorg/ai/reviewer
|
|
254
|
+
description: AI-powered code review
|
|
255
|
+
inputSchema:
|
|
256
|
+
type: object
|
|
257
|
+
properties:
|
|
258
|
+
code: { type: string }
|
|
259
|
+
required: [code]
|
|
260
|
+
outputSchema:
|
|
261
|
+
type: object
|
|
262
|
+
properties:
|
|
263
|
+
issues: { type: array }
|
|
264
|
+
score: { type: number }
|
|
265
|
+
---
|
|
266
|
+
# Code Reviewer
|
|
267
|
+
|
|
268
|
+
You are a senior engineer. Review the code for bugs, style, and security.
|
|
269
|
+
Return JSON: {"issues": [...], "score": 75}
|
|
270
|
+
\`\`\`
|
|
271
|
+
|
|
272
|
+
## Publishing Checklist
|
|
273
|
+
|
|
274
|
+
- [ ] \`name\` follows \`namespace/category/tool\` pattern
|
|
275
|
+
- [ ] \`version\` set (semver)
|
|
276
|
+
- [ ] \`description\` is clear and searchable
|
|
277
|
+
- [ ] \`inputSchema\` / \`outputSchema\` defined
|
|
278
|
+
- [ ] \`from\` uses pinned image version
|
|
279
|
+
- [ ] \`timeout\` set appropriately
|
|
280
|
+
- [ ] Tool tested locally with \`enact run ./\`
|
|
281
|
+
|
|
282
|
+
## Troubleshooting
|
|
283
|
+
|
|
284
|
+
\`\`\`bash
|
|
285
|
+
enact run ./ --args '{"x": "y"}' --verbose # Verbose output
|
|
286
|
+
enact run ./ --args '{}' --dry-run # Preview command
|
|
287
|
+
enact list # List installed tools
|
|
288
|
+
\`\`\`
|
|
131
289
|
`,
|
|
132
290
|
|
|
133
291
|
"agent-agents.md": `# AGENTS.md
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* enact learn command
|
|
3
|
+
*
|
|
4
|
+
* Display the documentation (enact.md) for a tool.
|
|
5
|
+
* Fetches and displays the raw manifest content for easy reading.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { createApiClient, getToolInfo, getToolVersion } from "@enactprotocol/api";
|
|
9
|
+
import { loadConfig } from "@enactprotocol/shared";
|
|
10
|
+
import type { Command } from "commander";
|
|
11
|
+
import type { CommandContext, GlobalOptions } from "../../types";
|
|
12
|
+
import { dim, error, formatError, header, json, newline } from "../../utils";
|
|
13
|
+
|
|
14
|
+
interface LearnOptions extends GlobalOptions {
|
|
15
|
+
ver?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Learn command handler
|
|
20
|
+
*/
|
|
21
|
+
async function learnHandler(
|
|
22
|
+
toolName: string,
|
|
23
|
+
options: LearnOptions,
|
|
24
|
+
_ctx: CommandContext
|
|
25
|
+
): Promise<void> {
|
|
26
|
+
const config = loadConfig();
|
|
27
|
+
const registryUrl =
|
|
28
|
+
process.env.ENACT_REGISTRY_URL ??
|
|
29
|
+
config.registry?.url ??
|
|
30
|
+
"https://siikwkfgsmouioodghho.supabase.co/functions/v1";
|
|
31
|
+
const authToken = config.registry?.authToken;
|
|
32
|
+
const client = createApiClient({
|
|
33
|
+
baseUrl: registryUrl,
|
|
34
|
+
authToken: authToken,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
// Get the version to fetch - either specified or latest
|
|
39
|
+
let version = options.ver;
|
|
40
|
+
if (!version) {
|
|
41
|
+
const toolInfo = await getToolInfo(client, toolName);
|
|
42
|
+
version = toolInfo.latestVersion;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Get the version info which includes rawManifest
|
|
46
|
+
const versionInfo = await getToolVersion(client, toolName, version);
|
|
47
|
+
|
|
48
|
+
if (options.json) {
|
|
49
|
+
json({
|
|
50
|
+
name: toolName,
|
|
51
|
+
version: versionInfo.version,
|
|
52
|
+
documentation: versionInfo.rawManifest ?? null,
|
|
53
|
+
});
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (!versionInfo.rawManifest) {
|
|
58
|
+
error(`No documentation found for ${toolName}@${version}`);
|
|
59
|
+
dim("This tool may not have an enact.md file.");
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Display the documentation
|
|
64
|
+
header(`${toolName}@${version}`);
|
|
65
|
+
newline();
|
|
66
|
+
console.log(versionInfo.rawManifest);
|
|
67
|
+
} catch (err) {
|
|
68
|
+
if (err instanceof Error) {
|
|
69
|
+
if (err.message.includes("not_found") || err.message.includes("404")) {
|
|
70
|
+
error(`Tool not found: ${toolName}`);
|
|
71
|
+
dim("Check the tool name or search with: enact search <query>");
|
|
72
|
+
process.exit(1);
|
|
73
|
+
}
|
|
74
|
+
if (err.message.includes("fetch")) {
|
|
75
|
+
error("Unable to connect to registry. Check your internet connection.");
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
throw err;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Configure the learn command
|
|
85
|
+
*/
|
|
86
|
+
export function configureLearnCommand(program: Command): void {
|
|
87
|
+
program
|
|
88
|
+
.command("learn <tool>")
|
|
89
|
+
.description("Display documentation (enact.md) for a tool")
|
|
90
|
+
.option("--ver <version>", "Show documentation for a specific version")
|
|
91
|
+
.option("--json", "Output as JSON")
|
|
92
|
+
.action(async (toolName: string, options: LearnOptions) => {
|
|
93
|
+
const ctx: CommandContext = {
|
|
94
|
+
cwd: process.cwd(),
|
|
95
|
+
options,
|
|
96
|
+
isCI: Boolean(process.env.CI),
|
|
97
|
+
isInteractive: process.stdout.isTTY ?? false,
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
try {
|
|
101
|
+
await learnHandler(toolName, options, ctx);
|
|
102
|
+
} catch (err) {
|
|
103
|
+
error(formatError(err));
|
|
104
|
+
process.exit(1);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
}
|
|
@@ -61,6 +61,7 @@ import {
|
|
|
61
61
|
|
|
62
62
|
interface RunOptions extends GlobalOptions {
|
|
63
63
|
args?: string;
|
|
64
|
+
inputFile?: string;
|
|
64
65
|
input?: string[];
|
|
65
66
|
timeout?: string;
|
|
66
67
|
noCache?: boolean;
|
|
@@ -70,14 +71,46 @@ interface RunOptions extends GlobalOptions {
|
|
|
70
71
|
|
|
71
72
|
/**
|
|
72
73
|
* Parse input arguments from various formats
|
|
74
|
+
*
|
|
75
|
+
* Priority order (later sources override earlier):
|
|
76
|
+
* 1. --input-file (JSON file)
|
|
77
|
+
* 2. --args (inline JSON)
|
|
78
|
+
* 3. --input (key=value pairs)
|
|
79
|
+
*
|
|
80
|
+
* Recommended for agents: Use --args or --input-file with JSON
|
|
73
81
|
*/
|
|
74
82
|
function parseInputArgs(
|
|
75
83
|
argsJson: string | undefined,
|
|
84
|
+
inputFile: string | undefined,
|
|
76
85
|
inputFlags: string[] | undefined
|
|
77
86
|
): Record<string, unknown> {
|
|
78
87
|
const inputs: Record<string, unknown> = {};
|
|
79
88
|
|
|
80
|
-
// Parse --
|
|
89
|
+
// Parse --input-file JSON file (loaded first, can be overridden)
|
|
90
|
+
if (inputFile) {
|
|
91
|
+
try {
|
|
92
|
+
const { readFileSync, existsSync } = require("node:fs");
|
|
93
|
+
const { resolve } = require("node:path");
|
|
94
|
+
const filePath = resolve(inputFile);
|
|
95
|
+
|
|
96
|
+
if (!existsSync(filePath)) {
|
|
97
|
+
throw new Error(`Input file not found: ${inputFile}`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const content = readFileSync(filePath, "utf-8");
|
|
101
|
+
const parsed = JSON.parse(content);
|
|
102
|
+
if (typeof parsed === "object" && parsed !== null) {
|
|
103
|
+
Object.assign(inputs, parsed);
|
|
104
|
+
}
|
|
105
|
+
} catch (err) {
|
|
106
|
+
if (err instanceof Error && err.message.startsWith("Input file not found")) {
|
|
107
|
+
throw err;
|
|
108
|
+
}
|
|
109
|
+
throw new Error(`Invalid JSON in input file: ${formatError(err)}`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Parse --args JSON (overrides file)
|
|
81
114
|
if (argsJson) {
|
|
82
115
|
try {
|
|
83
116
|
const parsed = JSON.parse(argsJson);
|
|
@@ -89,7 +122,7 @@ function parseInputArgs(
|
|
|
89
122
|
}
|
|
90
123
|
}
|
|
91
124
|
|
|
92
|
-
// Parse --input key=value pairs
|
|
125
|
+
// Parse --input key=value pairs (overrides both)
|
|
93
126
|
if (inputFlags) {
|
|
94
127
|
for (const input of inputFlags) {
|
|
95
128
|
const eqIndex = input.indexOf("=");
|
|
@@ -501,7 +534,7 @@ async function runHandler(tool: string, options: RunOptions, ctx: CommandContext
|
|
|
501
534
|
const manifest = resolution.manifest;
|
|
502
535
|
|
|
503
536
|
// Parse inputs
|
|
504
|
-
const inputs = parseInputArgs(options.args, options.input);
|
|
537
|
+
const inputs = parseInputArgs(options.args, options.inputFile, options.input);
|
|
505
538
|
|
|
506
539
|
// Apply defaults from schema
|
|
507
540
|
const inputsWithDefaults = manifest.inputSchema
|
|
@@ -669,8 +702,9 @@ export function configureRunCommand(program: Command): void {
|
|
|
669
702
|
.command("run")
|
|
670
703
|
.description("Execute a tool with its manifest-defined command")
|
|
671
704
|
.argument("<tool>", "Tool to run (name, path, or '.' for current directory)")
|
|
672
|
-
.option("-a, --args <json>", "Input arguments as JSON")
|
|
673
|
-
.option("-
|
|
705
|
+
.option("-a, --args <json>", "Input arguments as JSON string (recommended)")
|
|
706
|
+
.option("-f, --input-file <path>", "Load input arguments from JSON file")
|
|
707
|
+
.option("-i, --input <key=value...>", "Input arguments as key=value pairs (simple values only)")
|
|
674
708
|
.option("-t, --timeout <duration>", "Execution timeout (e.g., 30s, 5m)")
|
|
675
709
|
.option("--no-cache", "Disable container caching")
|
|
676
710
|
.option("--local", "Only resolve from local sources")
|
package/src/index.ts
CHANGED
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
configureInitCommand,
|
|
20
20
|
configureInspectCommand,
|
|
21
21
|
configureInstallCommand,
|
|
22
|
+
configureLearnCommand,
|
|
22
23
|
configureListCommand,
|
|
23
24
|
configurePublishCommand,
|
|
24
25
|
configureReportCommand,
|
|
@@ -32,7 +33,7 @@ import {
|
|
|
32
33
|
} from "./commands";
|
|
33
34
|
import { error, formatError } from "./utils";
|
|
34
35
|
|
|
35
|
-
export const version = "2.1.
|
|
36
|
+
export const version = "2.1.6";
|
|
36
37
|
|
|
37
38
|
// Export types for external use
|
|
38
39
|
export type { GlobalOptions, CommandContext } from "./types";
|
|
@@ -47,7 +48,7 @@ async function main() {
|
|
|
47
48
|
program
|
|
48
49
|
.name("enact")
|
|
49
50
|
.description("Enact - Verified, portable protocol for AI-executable tools")
|
|
50
|
-
.version(version);
|
|
51
|
+
.version(version, "-v, --version", "output the version number");
|
|
51
52
|
|
|
52
53
|
// Configure all commands
|
|
53
54
|
configureSetupCommand(program);
|
|
@@ -63,6 +64,7 @@ async function main() {
|
|
|
63
64
|
// Registry commands (Phase 8)
|
|
64
65
|
configureSearchCommand(program);
|
|
65
66
|
configureGetCommand(program);
|
|
67
|
+
configureLearnCommand(program);
|
|
66
68
|
configurePublishCommand(program);
|
|
67
69
|
configureAuthCommand(program);
|
|
68
70
|
configureCacheCommand(program);
|
|
@@ -352,7 +352,7 @@ describe("init command", () => {
|
|
|
352
352
|
rmSync(testDir, { recursive: true });
|
|
353
353
|
});
|
|
354
354
|
|
|
355
|
-
test("AGENTS.md
|
|
355
|
+
test("AGENTS.md is comprehensive but reasonably sized", async () => {
|
|
356
356
|
const program = new Command();
|
|
357
357
|
program.exitOverride();
|
|
358
358
|
configureInitCommand(program);
|
|
@@ -376,9 +376,10 @@ describe("init command", () => {
|
|
|
376
376
|
|
|
377
377
|
const content = readFileSync(join(testDir, "AGENTS.md"), "utf-8");
|
|
378
378
|
|
|
379
|
-
// Should be
|
|
379
|
+
// Should be comprehensive but not excessive
|
|
380
380
|
const lines = content.split("\n").length;
|
|
381
|
-
expect(lines).toBeLessThan(
|
|
381
|
+
expect(lines).toBeLessThan(250); // Comprehensive guide under 250 lines
|
|
382
|
+
expect(lines).toBeGreaterThan(100); // But not too sparse
|
|
382
383
|
|
|
383
384
|
// Clean up
|
|
384
385
|
rmSync(testDir, { recursive: true });
|