@foldspace_npm/harness 0.1.3 → 0.1.4
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 +6 -4
- package/bin/cli.mjs +16 -9
- package/package.json +1 -1
- package/src/cli-help.mjs +4 -0
- package/src/cli-registry.mjs +4 -3
- package/src/init.mjs +18 -7
package/README.md
CHANGED
|
@@ -95,7 +95,7 @@ Non-interactive / CI form:
|
|
|
95
95
|
```bash
|
|
96
96
|
npx --yes @foldspace_npm/harness init my-agent \
|
|
97
97
|
--product-id FR8JUQZAQRZB \
|
|
98
|
-
--agent-
|
|
98
|
+
--agent-key my-agent \
|
|
99
99
|
--domain app.example.com \
|
|
100
100
|
--name "My Agent"
|
|
101
101
|
```
|
|
@@ -105,12 +105,14 @@ When running directly from a harness checkout during development:
|
|
|
105
105
|
```bash
|
|
106
106
|
node bin/cli.mjs init ../my-agent \
|
|
107
107
|
--product-id FR8JUQZAQRZB \
|
|
108
|
-
--agent-
|
|
108
|
+
--agent-key my-agent \
|
|
109
109
|
--domain app.example.com
|
|
110
110
|
```
|
|
111
111
|
|
|
112
|
-
|
|
113
|
-
|
|
112
|
+
The Agent Key is the value shown in Agent Studio, such as `my-agent`.
|
|
113
|
+
`--agent-api-name` remains a deprecated alias for `--agent-key`. `--name` is
|
|
114
|
+
optional and defaults to the target directory name. The product ID must be the
|
|
115
|
+
bare ID, not the `EU-…-1-1` SDK loader key. The domain may be a hostname or an
|
|
114
116
|
HTTP(S) URL without a port or path.
|
|
115
117
|
|
|
116
118
|
For safety, `init` requires a target path that does not exist. It does not
|
package/bin/cli.mjs
CHANGED
|
@@ -62,9 +62,13 @@ function printHelp(topic, json) {
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
function normalizeCommandArgs(command, args) {
|
|
65
|
-
const options = new Map(
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
const options = new Map();
|
|
66
|
+
for (const option of command.options) {
|
|
67
|
+
options.set(option.name, { option, canonicalName: option.name });
|
|
68
|
+
for (const alias of option.deprecatedAliases || []) {
|
|
69
|
+
options.set(alias, { option, canonicalName: option.name });
|
|
70
|
+
}
|
|
71
|
+
}
|
|
68
72
|
const seen = new Set();
|
|
69
73
|
const normalized = [];
|
|
70
74
|
let positionals = 0;
|
|
@@ -81,14 +85,17 @@ function normalizeCommandArgs(command, args) {
|
|
|
81
85
|
|
|
82
86
|
const separator = token.indexOf("=");
|
|
83
87
|
const name = separator > -1 ? token.slice(0, separator) : token;
|
|
84
|
-
const
|
|
85
|
-
if (!
|
|
86
|
-
|
|
87
|
-
seen.
|
|
88
|
+
const match = options.get(name);
|
|
89
|
+
if (!match) throw new Error(`unknown option '${name}'`);
|
|
90
|
+
const { option, canonicalName } = match;
|
|
91
|
+
if (seen.has(canonicalName)) {
|
|
92
|
+
throw new Error(`option '${canonicalName}' was provided twice`);
|
|
93
|
+
}
|
|
94
|
+
seen.add(canonicalName);
|
|
88
95
|
|
|
89
96
|
if (option.kind === "flag") {
|
|
90
97
|
if (separator > -1) throw new Error(`option '${name}' takes no value`);
|
|
91
|
-
normalized.push(
|
|
98
|
+
normalized.push(canonicalName);
|
|
92
99
|
continue;
|
|
93
100
|
}
|
|
94
101
|
|
|
@@ -97,7 +104,7 @@ function normalizeCommandArgs(command, args) {
|
|
|
97
104
|
if (!optionValue || optionValue.startsWith("--")) {
|
|
98
105
|
throw new Error(`option '${name}' requires a value`);
|
|
99
106
|
}
|
|
100
|
-
normalized.push(
|
|
107
|
+
normalized.push(canonicalName, optionValue);
|
|
101
108
|
}
|
|
102
109
|
return normalized;
|
|
103
110
|
}
|
package/package.json
CHANGED
package/src/cli-help.mjs
CHANGED
|
@@ -74,6 +74,10 @@ export function renderCommandHelp(registry, name) {
|
|
|
74
74
|
`${option.name}${option.value ? ` <${option.value}>` : ""}`,
|
|
75
75
|
`${option.description}${
|
|
76
76
|
option.default ? ` (default: ${option.default})` : ""
|
|
77
|
+
}${
|
|
78
|
+
option.deprecatedAliases?.length
|
|
79
|
+
? ` (deprecated alias: ${option.deprecatedAliases.join(", ")})`
|
|
80
|
+
: ""
|
|
77
81
|
}`,
|
|
78
82
|
]);
|
|
79
83
|
sections.push("", "Options:", rows(optionRows));
|
package/src/cli-registry.mjs
CHANGED
|
@@ -21,7 +21,7 @@ export const CLI_COMMANDS = Object.freeze([
|
|
|
21
21
|
group: "start",
|
|
22
22
|
summary: "Create a configured Foldspace actions project",
|
|
23
23
|
usage:
|
|
24
|
-
"foldspace init [<directory>] [--product-id <id>] [--agent-
|
|
24
|
+
"foldspace init [<directory>] [--product-id <id>] [--agent-key <key>] [--domain <host>] [--name <display-name>]",
|
|
25
25
|
risk: "local-write",
|
|
26
26
|
environment: "node",
|
|
27
27
|
environmentVariables: [],
|
|
@@ -37,8 +37,9 @@ export const CLI_COMMANDS = Object.freeze([
|
|
|
37
37
|
value("--product-id", "id", "Bare Foldspace product ID", {
|
|
38
38
|
required: "non-interactive",
|
|
39
39
|
}),
|
|
40
|
-
value("--agent-
|
|
40
|
+
value("--agent-key", "key", "Agent Key shown in Agent Studio", {
|
|
41
41
|
required: "non-interactive",
|
|
42
|
+
deprecatedAliases: ["--agent-api-name"],
|
|
42
43
|
}),
|
|
43
44
|
value("--domain", "host", "Target hostname or HTTP(S) URL", {
|
|
44
45
|
required: "non-interactive",
|
|
@@ -50,7 +51,7 @@ export const CLI_COMMANDS = Object.freeze([
|
|
|
50
51
|
prerequisites: [
|
|
51
52
|
"Node 20 or newer",
|
|
52
53
|
"A target directory that does not already exist",
|
|
53
|
-
"Non-interactive use requires directory, product ID,
|
|
54
|
+
"Non-interactive use requires directory, product ID, Agent Key, and domain",
|
|
54
55
|
],
|
|
55
56
|
effects: ["Creates a new local project; never initializes Git"],
|
|
56
57
|
next: [
|
package/src/init.mjs
CHANGED
|
@@ -8,7 +8,13 @@ import { commandByName } from "./cli-registry.mjs";
|
|
|
8
8
|
|
|
9
9
|
const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
10
10
|
const defaultTemplateRoot = path.join(packageRoot, "templates", "agent-starter");
|
|
11
|
-
const allowedFlags = new Set([
|
|
11
|
+
const allowedFlags = new Set([
|
|
12
|
+
"name",
|
|
13
|
+
"product-id",
|
|
14
|
+
"agent-key",
|
|
15
|
+
"agent-api-name",
|
|
16
|
+
"domain",
|
|
17
|
+
]);
|
|
12
18
|
const tokenPattern = /\{\{([A-Z0-9_]+)\}\}/g;
|
|
13
19
|
const defaultDirectory = "my-agent";
|
|
14
20
|
|
|
@@ -75,12 +81,17 @@ export function parseInitArgs(argv) {
|
|
|
75
81
|
if (positional.length > 1) {
|
|
76
82
|
throw new Error(`Usage: ${initUsage}`);
|
|
77
83
|
}
|
|
84
|
+
if (flags["agent-key"] && flags["agent-api-name"]) {
|
|
85
|
+
throw new Error(
|
|
86
|
+
"Use --agent-key only; --agent-api-name is its deprecated alias.",
|
|
87
|
+
);
|
|
88
|
+
}
|
|
78
89
|
|
|
79
90
|
return {
|
|
80
91
|
directory: positional[0] || null,
|
|
81
92
|
displayName: flags.name || null,
|
|
82
93
|
productId: flags["product-id"] || null,
|
|
83
|
-
agentApiName: flags["agent-api-name"] || null,
|
|
94
|
+
agentApiName: flags["agent-key"] || flags["agent-api-name"] || null,
|
|
84
95
|
domain: flags.domain || null,
|
|
85
96
|
};
|
|
86
97
|
}
|
|
@@ -89,7 +100,7 @@ function missingInitFields(parsed) {
|
|
|
89
100
|
const missing = [];
|
|
90
101
|
if (!parsed.directory) missing.push("directory");
|
|
91
102
|
if (!parsed.productId) missing.push("product-id");
|
|
92
|
-
if (!parsed.agentApiName) missing.push("agent-
|
|
103
|
+
if (!parsed.agentApiName) missing.push("agent-key");
|
|
93
104
|
if (!parsed.domain) missing.push("domain");
|
|
94
105
|
return missing;
|
|
95
106
|
}
|
|
@@ -208,8 +219,8 @@ async function promptForMissingFields(parsed, options = {}) {
|
|
|
208
219
|
|
|
209
220
|
if (!next.agentApiName) {
|
|
210
221
|
next.agentApiName = await askUntilValid(
|
|
211
|
-
"Agent
|
|
212
|
-
(value) => validateIdentifier(value, "Agent
|
|
222
|
+
"Agent Key",
|
|
223
|
+
(value) => validateIdentifier(value, "Agent Key"),
|
|
213
224
|
options,
|
|
214
225
|
);
|
|
215
226
|
}
|
|
@@ -243,7 +254,7 @@ function finalizeInitConfig(parsed) {
|
|
|
243
254
|
|
|
244
255
|
for (const [key, label] of [
|
|
245
256
|
["productId", "product-id"],
|
|
246
|
-
["agentApiName", "agent-
|
|
257
|
+
["agentApiName", "agent-key"],
|
|
247
258
|
["domain", "domain"],
|
|
248
259
|
]) {
|
|
249
260
|
if (!parsed[key]) {
|
|
@@ -282,7 +293,7 @@ function createTemplateValues(config, harnessVersion) {
|
|
|
282
293
|
}
|
|
283
294
|
|
|
284
295
|
const productId = validateProductId(config.productId);
|
|
285
|
-
const agentApiName = validateIdentifier(config.agentApiName, "Agent
|
|
296
|
+
const agentApiName = validateIdentifier(config.agentApiName, "Agent Key");
|
|
286
297
|
const target = normalizeTarget(config.domain);
|
|
287
298
|
const hosts =
|
|
288
299
|
target.domain === "localhost" || /^\d+(?:\.\d+){3}$/.test(target.domain)
|