@foldspace_npm/harness 0.1.2 → 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 +67 -16
- package/bin/attach.mjs +779 -107
- package/bin/cli.mjs +129 -44
- package/bin/deploy.mjs +37 -33
- package/bin/inject.mjs +64 -295
- package/package.json +5 -2
- package/src/action-observer.mjs +271 -0
- package/src/attach-helpers.mjs +162 -0
- package/src/attach-preflight.mjs +332 -0
- package/src/bootstrap-script.mjs +120 -0
- package/src/cdp-request-manager.mjs +61 -0
- package/src/cli-help.mjs +147 -0
- package/src/cli-registry.mjs +310 -0
- package/src/diagnostics.mjs +482 -0
- package/src/init.mjs +20 -9
- package/src/project-config.mjs +37 -0
- package/src/protocol.mjs +181 -0
- package/src/session-summary.mjs +133 -0
- package/templates/agent-starter/CLAUDE.md +31 -8
- package/templates/agent-starter/README.md +26 -3
- package/templates/agent-starter/foldspace.dev.json +1 -3
- package/bin/buildExtension.mjs +0 -90
- package/bin/packageExtension.mjs +0 -29
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
import { diagnosticCatalogue } from "./diagnostics.mjs";
|
|
2
|
+
import { HARNESS_PROTOCOL_VERSION } from "./protocol.mjs";
|
|
3
|
+
|
|
4
|
+
export const CLI_SCHEMA_VERSION = 1;
|
|
5
|
+
|
|
6
|
+
const flag = (name, description, details = {}) =>
|
|
7
|
+
Object.freeze({ name, kind: "flag", description, ...details });
|
|
8
|
+
const value = (name, valueName, description, details = {}) =>
|
|
9
|
+
Object.freeze({
|
|
10
|
+
name,
|
|
11
|
+
kind: "value",
|
|
12
|
+
value: valueName,
|
|
13
|
+
description,
|
|
14
|
+
...details,
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
export const CLI_COMMANDS = Object.freeze([
|
|
18
|
+
Object.freeze({
|
|
19
|
+
name: "init",
|
|
20
|
+
entry: null,
|
|
21
|
+
group: "start",
|
|
22
|
+
summary: "Create a configured Foldspace actions project",
|
|
23
|
+
usage:
|
|
24
|
+
"foldspace init [<directory>] [--product-id <id>] [--agent-key <key>] [--domain <host>] [--name <display-name>]",
|
|
25
|
+
risk: "local-write",
|
|
26
|
+
environment: "node",
|
|
27
|
+
environmentVariables: [],
|
|
28
|
+
capabilities: ["project.scaffold"],
|
|
29
|
+
positionals: [
|
|
30
|
+
{
|
|
31
|
+
name: "directory",
|
|
32
|
+
required: "non-interactive",
|
|
33
|
+
description: "New project directory",
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
options: [
|
|
37
|
+
value("--product-id", "id", "Bare Foldspace product ID", {
|
|
38
|
+
required: "non-interactive",
|
|
39
|
+
}),
|
|
40
|
+
value("--agent-key", "key", "Agent Key shown in Agent Studio", {
|
|
41
|
+
required: "non-interactive",
|
|
42
|
+
deprecatedAliases: ["--agent-api-name"],
|
|
43
|
+
}),
|
|
44
|
+
value("--domain", "host", "Target hostname or HTTP(S) URL", {
|
|
45
|
+
required: "non-interactive",
|
|
46
|
+
}),
|
|
47
|
+
value("--name", "display-name", "Display name", {
|
|
48
|
+
default: "directory name",
|
|
49
|
+
}),
|
|
50
|
+
],
|
|
51
|
+
prerequisites: [
|
|
52
|
+
"Node 20 or newer",
|
|
53
|
+
"A target directory that does not already exist",
|
|
54
|
+
"Non-interactive use requires directory, product ID, Agent Key, and domain",
|
|
55
|
+
],
|
|
56
|
+
effects: ["Creates a new local project; never initializes Git"],
|
|
57
|
+
next: [
|
|
58
|
+
"Install dependencies",
|
|
59
|
+
"Run foldspace build",
|
|
60
|
+
"Run foldspace inject",
|
|
61
|
+
"Run foldspace attach",
|
|
62
|
+
],
|
|
63
|
+
}),
|
|
64
|
+
Object.freeze({
|
|
65
|
+
name: "build",
|
|
66
|
+
entry: "build-cli.mjs",
|
|
67
|
+
group: "develop",
|
|
68
|
+
summary: "Bundle agent actions to dist/index.js",
|
|
69
|
+
usage: "foldspace build [--watch]",
|
|
70
|
+
risk: "local-write",
|
|
71
|
+
environment: "node",
|
|
72
|
+
environmentVariables: ["FOLDSPACE_PROJECT_DIR"],
|
|
73
|
+
capabilities: ["artifact.build"],
|
|
74
|
+
positionals: [],
|
|
75
|
+
options: [flag("--watch", "Rebuild when action source changes")],
|
|
76
|
+
prerequisites: ["agent/actions/index.ts"],
|
|
77
|
+
effects: ["Writes dist/index.js"],
|
|
78
|
+
next: ["Run foldspace inject", "Run foldspace attach"],
|
|
79
|
+
}),
|
|
80
|
+
Object.freeze({
|
|
81
|
+
name: "inject",
|
|
82
|
+
entry: "inject.mjs",
|
|
83
|
+
group: "verify",
|
|
84
|
+
summary: "Launch an isolated Chrome profile for local verification",
|
|
85
|
+
usage: "foldspace inject [options]",
|
|
86
|
+
risk: "browser-session",
|
|
87
|
+
environment: "local-chrome",
|
|
88
|
+
environmentVariables: ["FOLDSPACE_PROJECT_DIR", "CHROME_PATH"],
|
|
89
|
+
capabilities: ["browser.launch", "browser.cdp"],
|
|
90
|
+
positionals: [],
|
|
91
|
+
options: [
|
|
92
|
+
value("--target", "name", "Use a target from foldspace.dev.json"),
|
|
93
|
+
value("--url", "url", "Override the target start URL"),
|
|
94
|
+
value("--product", "id", "Override the local-session product ID"),
|
|
95
|
+
value("--agent", "api-name", "Override the local-session agent"),
|
|
96
|
+
value("--hosts", "a,b", "Override allowed host patterns"),
|
|
97
|
+
value(
|
|
98
|
+
"--key",
|
|
99
|
+
"sdk-key",
|
|
100
|
+
"Override the SDK key used later by attach/bootstrap",
|
|
101
|
+
),
|
|
102
|
+
flag("--embedded", "Use EMBEDDED mode for the local session"),
|
|
103
|
+
value("--port", "number", "Chrome debugging port", {
|
|
104
|
+
default: "9222",
|
|
105
|
+
}),
|
|
106
|
+
flag(
|
|
107
|
+
"--print",
|
|
108
|
+
"Resolve and print the target without writing or launching",
|
|
109
|
+
),
|
|
110
|
+
],
|
|
111
|
+
prerequisites: [
|
|
112
|
+
"foldspace.dev.json",
|
|
113
|
+
"Local Chrome unless --print",
|
|
114
|
+
"Using --url without --target also requires --product and --agent",
|
|
115
|
+
],
|
|
116
|
+
effects: [
|
|
117
|
+
"With --print, writes nothing and launches nothing",
|
|
118
|
+
"Otherwise creates an isolated profile and writes .foldspace-dev/state.json",
|
|
119
|
+
"Does not load the SDK or action artifact",
|
|
120
|
+
],
|
|
121
|
+
next: ["Sign in to the target application", "Run foldspace attach"],
|
|
122
|
+
}),
|
|
123
|
+
Object.freeze({
|
|
124
|
+
name: "attach",
|
|
125
|
+
entry: "attach.mjs",
|
|
126
|
+
group: "verify",
|
|
127
|
+
summary:
|
|
128
|
+
"Load local actions over CDP and observe the normal agent experience",
|
|
129
|
+
usage:
|
|
130
|
+
"foldspace attach [--bootstrap | --replace] [--target <name>] [--port <number>] [--agent <api-name>] [--no-test-mode] [--no-badge]",
|
|
131
|
+
risk: "browser-session",
|
|
132
|
+
environment: "local-chrome",
|
|
133
|
+
environmentVariables: [
|
|
134
|
+
"FOLDSPACE_PROJECT_DIR",
|
|
135
|
+
"CDP_PORT",
|
|
136
|
+
"AGENT_API_NAME",
|
|
137
|
+
],
|
|
138
|
+
capabilities: [
|
|
139
|
+
"browser.cdp",
|
|
140
|
+
"artifact.load",
|
|
141
|
+
"page.evaluate",
|
|
142
|
+
"page.mutate",
|
|
143
|
+
],
|
|
144
|
+
positionals: [],
|
|
145
|
+
modes: [
|
|
146
|
+
{
|
|
147
|
+
name: "swap",
|
|
148
|
+
flag: null,
|
|
149
|
+
description:
|
|
150
|
+
"Default; page already has the configured product and agent",
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
name: "bootstrap",
|
|
154
|
+
flag: "--bootstrap",
|
|
155
|
+
description: "Page has no Foldspace SDK",
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
name: "replace",
|
|
159
|
+
flag: "--replace",
|
|
160
|
+
description: "Page has a different product or agent",
|
|
161
|
+
},
|
|
162
|
+
],
|
|
163
|
+
options: [
|
|
164
|
+
flag("--bootstrap", "Prepare a page that has no Foldspace SDK"),
|
|
165
|
+
flag(
|
|
166
|
+
"--replace",
|
|
167
|
+
"Temporarily replace a different page product or agent",
|
|
168
|
+
),
|
|
169
|
+
value("--target", "name", "Use a target from foldspace.dev.json"),
|
|
170
|
+
value(
|
|
171
|
+
"--port",
|
|
172
|
+
"number",
|
|
173
|
+
"CDP port: CLI, CDP_PORT, saved launch state, then 9222",
|
|
174
|
+
),
|
|
175
|
+
value("--agent", "api-name", "Override the configured agent API name"),
|
|
176
|
+
flag(
|
|
177
|
+
"--no-test-mode",
|
|
178
|
+
"Do not mark conversations as test traffic; use deliberately",
|
|
179
|
+
),
|
|
180
|
+
flag("--no-badge", "Hide the visible Foldspace development badge"),
|
|
181
|
+
],
|
|
182
|
+
prerequisites: [
|
|
183
|
+
"foldspace.dev.json",
|
|
184
|
+
"dist/index.js",
|
|
185
|
+
"A Chrome CDP endpoint, normally created by foldspace inject",
|
|
186
|
+
"sdkUrl in foldspace.dev.json when using --bootstrap",
|
|
187
|
+
],
|
|
188
|
+
effects: [
|
|
189
|
+
"May reload and instrument matching target pages",
|
|
190
|
+
"Test mode is enabled unless --no-test-mode is passed",
|
|
191
|
+
"Never directly invokes an action handler",
|
|
192
|
+
"Restores prepared pages when detached cleanly",
|
|
193
|
+
],
|
|
194
|
+
next: [
|
|
195
|
+
"Exercise the visible agent normally",
|
|
196
|
+
"Confirm [lifecycle] inspect_registration:registration_ok",
|
|
197
|
+
"Confirm execute/render observations",
|
|
198
|
+
"Detach with Ctrl-C",
|
|
199
|
+
],
|
|
200
|
+
}),
|
|
201
|
+
Object.freeze({
|
|
202
|
+
name: "deploy",
|
|
203
|
+
entry: "deploy.mjs",
|
|
204
|
+
group: "publish",
|
|
205
|
+
summary: "Publish dist/index.js to remote Foldspace action storage",
|
|
206
|
+
usage:
|
|
207
|
+
"foldspace deploy [--target <name>] [--env <dev|prod>]",
|
|
208
|
+
risk: "remote-publish",
|
|
209
|
+
environment: "local-cloud-credentials",
|
|
210
|
+
environmentVariables: ["FOLDSPACE_PROJECT_DIR"],
|
|
211
|
+
capabilities: ["artifact.publish"],
|
|
212
|
+
positionals: [],
|
|
213
|
+
options: [
|
|
214
|
+
value(
|
|
215
|
+
"--target",
|
|
216
|
+
"name",
|
|
217
|
+
"Target from foldspace.dev.json",
|
|
218
|
+
{ default: "defaultTarget" },
|
|
219
|
+
),
|
|
220
|
+
value("--env", "dev|prod", "Remote environment", { default: "dev" }),
|
|
221
|
+
],
|
|
222
|
+
prerequisites: [
|
|
223
|
+
"foldspace.dev.json",
|
|
224
|
+
"dist/index.js",
|
|
225
|
+
"A Git commit",
|
|
226
|
+
"Authenticated gsutil/gcloud",
|
|
227
|
+
],
|
|
228
|
+
effects: [
|
|
229
|
+
"Uploads versioned and latest JavaScript objects",
|
|
230
|
+
"Updates DEPLOYMENTS.md",
|
|
231
|
+
"Skips when the current Git SHA already exists remotely",
|
|
232
|
+
"Does not rebuild or verify that dist/index.js matches the current Git SHA",
|
|
233
|
+
],
|
|
234
|
+
next: ["Verify the remote artifact before production use"],
|
|
235
|
+
}),
|
|
236
|
+
]);
|
|
237
|
+
|
|
238
|
+
export const CAPABILITY_CATALOGUE = Object.freeze([
|
|
239
|
+
["project.scaffold", "Create a new configured project on local disk"],
|
|
240
|
+
["artifact.build", "Build the portable dist/index.js action artifact"],
|
|
241
|
+
["browser.launch", "Launch an isolated local Chrome profile"],
|
|
242
|
+
["browser.cdp", "Connect to local Chrome through CDP"],
|
|
243
|
+
["artifact.load", "Load a local action artifact into an authorized page"],
|
|
244
|
+
["page.evaluate", "Inspect bounded SDK and registration state"],
|
|
245
|
+
["page.mutate", "Prepare and restore a matching development page"],
|
|
246
|
+
["artifact.publish", "Write the built artifact to remote storage"],
|
|
247
|
+
]);
|
|
248
|
+
|
|
249
|
+
export const RISK_CATALOGUE = Object.freeze([
|
|
250
|
+
["local-write", "Writes only inside the consuming project"],
|
|
251
|
+
["browser-session", "Launches or temporarily mutates a local browser session"],
|
|
252
|
+
["remote-publish", "Writes the action artifact to remote storage"],
|
|
253
|
+
]);
|
|
254
|
+
|
|
255
|
+
export const ENVIRONMENT_CATALOGUE = Object.freeze([
|
|
256
|
+
["node", "Node.js workspace; no browser required"],
|
|
257
|
+
["local-chrome", "Local Chrome with an authorized CDP connection"],
|
|
258
|
+
[
|
|
259
|
+
"local-cloud-credentials",
|
|
260
|
+
"Local process with authenticated gsutil/gcloud",
|
|
261
|
+
],
|
|
262
|
+
]);
|
|
263
|
+
|
|
264
|
+
const PUBLIC_DIAGNOSTICS = new Set([
|
|
265
|
+
"inspectSdkState",
|
|
266
|
+
"inspectRegistration",
|
|
267
|
+
"verifyWidgetVisible",
|
|
268
|
+
"inspectActionObservation",
|
|
269
|
+
]);
|
|
270
|
+
|
|
271
|
+
export function commandByName(name) {
|
|
272
|
+
return CLI_COMMANDS.find((command) => command.name === name) || null;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
export function createCliRegistry({ packageName, packageVersion }) {
|
|
276
|
+
const diagnostics = diagnosticCatalogue()
|
|
277
|
+
.filter((diagnostic) => PUBLIC_DIAGNOSTICS.has(diagnostic.name))
|
|
278
|
+
.map((diagnostic) => ({
|
|
279
|
+
...diagnostic,
|
|
280
|
+
invocation: "attach-internal",
|
|
281
|
+
cliExposed: false,
|
|
282
|
+
}));
|
|
283
|
+
return {
|
|
284
|
+
kind: "foldspace.cli.help",
|
|
285
|
+
schemaVersion: CLI_SCHEMA_VERSION,
|
|
286
|
+
package: {
|
|
287
|
+
name: packageName,
|
|
288
|
+
version: packageVersion,
|
|
289
|
+
},
|
|
290
|
+
protocolVersion: HARNESS_PROTOCOL_VERSION,
|
|
291
|
+
workflow: ["init", "build", "inject", "attach"],
|
|
292
|
+
publishWorkflow: ["deploy"],
|
|
293
|
+
capabilities: CAPABILITY_CATALOGUE.map(([id, description]) => ({
|
|
294
|
+
id,
|
|
295
|
+
description,
|
|
296
|
+
})),
|
|
297
|
+
risks: RISK_CATALOGUE.map(([id, description]) => ({ id, description })),
|
|
298
|
+
environments: ENVIRONMENT_CATALOGUE.map(([id, description]) => ({
|
|
299
|
+
id,
|
|
300
|
+
description,
|
|
301
|
+
})),
|
|
302
|
+
commands: CLI_COMMANDS.map(({ entry: _entry, ...command }) => command),
|
|
303
|
+
diagnostics,
|
|
304
|
+
notes: [
|
|
305
|
+
"Capability metadata describes current behavior; it is not hosted-environment enforcement.",
|
|
306
|
+
"Action verification is passive and agent-driven.",
|
|
307
|
+
"The harness bin alias is equivalent to foldspace.",
|
|
308
|
+
],
|
|
309
|
+
};
|
|
310
|
+
}
|