@foldspace_npm/harness 0.1.20 → 0.1.21
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/CLAUDE.md +3 -2
- package/bin/attach.mjs +8 -23
- package/bin/badge.mjs +7 -7
- package/package.json +1 -1
- package/src/badge-core.mjs +2 -2
- package/src/cli-registry.mjs +5 -5
package/CLAUDE.md
CHANGED
|
@@ -77,8 +77,9 @@ at the app or testing in it, run `npx foldspace badge working` (a bar across
|
|
|
77
77
|
the top of the window says Foldspace is building here, leave it alone) and say
|
|
78
78
|
so in chat: *"I'm going to work in that Chrome window for a few minutes -
|
|
79
79
|
please leave it alone until I tell you it's ready."* When it is their turn,
|
|
80
|
-
`npx foldspace badge ready
|
|
81
|
-
|
|
80
|
+
`npx foldspace badge ready` takes the pill away (the small corner tag comes
|
|
81
|
+
back) and in chat you say what to try. No bar for their turn: they may type
|
|
82
|
+
whatever, whenever; the pill only ever asks them to wait. `foldspace badge label` puts the small
|
|
82
83
|
corner tag back; `off` removes it, for a screenshot they will share.
|
|
83
84
|
|
|
84
85
|
Navigation, uploads, extraction and anything that writes are a later session.
|
package/bin/attach.mjs
CHANGED
|
@@ -225,7 +225,8 @@ const SDK_PATTERNS = [
|
|
|
225
225
|
// label - the small corner tag (default): who is attached, which mode
|
|
226
226
|
// working - a pill at the foot of the window: the agent is building in this
|
|
227
227
|
// window, please leave it alone
|
|
228
|
-
// ready - the
|
|
228
|
+
// ready - the pill goes away and the small tag comes back: their turn.
|
|
229
|
+
// No bar for that - they may type whatever, whenever
|
|
229
230
|
// The pill sits bottom-left, never across the top: a bar there covered the
|
|
230
231
|
// app's own header and menu (seen on a CRM, 2026-09-22). The agent's panel
|
|
231
232
|
// is on the right, so bottom-left is the corner nothing else uses.
|
|
@@ -252,34 +253,18 @@ const badgeSrc = `(() => {
|
|
|
252
253
|
if (s.state === "working") {
|
|
253
254
|
// Attention, not decoration: a pulsing marker, the ask in bold, and an
|
|
254
255
|
// animated line underneath so it reads as "in progress" at a glance.
|
|
255
|
-
b.style.cssText = base + "top:auto;bottom:16px;left:16px;right:auto;max-width:min(560px,calc(100vw - 32px));border-radius:8px;overflow:hidden;background:#
|
|
256
|
+
b.style.cssText = base + "top:auto;bottom:16px;left:16px;right:auto;max-width:min(560px,calc(100vw - 32px));border-radius:8px;overflow:hidden;background:#3247F2;padding:10px 14px 13px;font-size:13px;letter-spacing:.02em;text-align:left;line-height:1.3;";
|
|
256
257
|
b.innerHTML =
|
|
257
258
|
'<style>@keyframes fsPulse{0%,100%{opacity:1}50%{opacity:.25}}@keyframes fsSweep{0%{left:-30%}100%{left:100%}}' +
|
|
258
|
-
'#foldspace-dev-badge .fs-dot{display:inline-block;width:10px;height:10px;border-radius:50%;background:#
|
|
259
|
+
'#foldspace-dev-badge .fs-dot{display:inline-block;width:10px;height:10px;border-radius:50%;background:#FFD314;margin-right:10px;vertical-align:middle;animation:fsPulse 1s ease-in-out infinite}' +
|
|
259
260
|
'#foldspace-dev-badge .fs-line{position:absolute;left:0;right:0;bottom:0;height:3px;background:rgba(255,255,255,.15);overflow:hidden}' +
|
|
260
|
-
'#foldspace-dev-badge .fs-line::after{content:"";position:absolute;top:0;width:30%;height:100%;background:#
|
|
261
|
-
'<span class="fs-dot"></span>Foldspace is building your agent on this page. <b style="color:#
|
|
261
|
+
'#foldspace-dev-badge .fs-line::after{content:"";position:absolute;top:0;width:30%;height:100%;background:#FFD314;animation:fsSweep 1.4s linear infinite}</style>' +
|
|
262
|
+
'<span class="fs-dot"></span>Foldspace is building your agent on this page. <b style="color:#FFD314">Please leave this window alone</b> until the agent says it is ready.' +
|
|
262
263
|
(s.text ? " " + s.text.replace(/[<>&]/g, (c) => ({ "<": "<", ">": ">", "&": "&" })[c]) : "") +
|
|
263
264
|
'<span class="fs-line"></span>';
|
|
264
|
-
} else if (s.state === "ready") {
|
|
265
|
-
// Calm, and useful: the question to try, with a Copy button so nobody
|
|
266
|
-
// retypes it into the panel. The bar accepts clicks only on that button.
|
|
267
|
-
const esc = (t) => String(t).replace(/[<>&"]/g, (c) => ({ "<": "<", ">": ">", "&": "&", '"': """ })[c]);
|
|
268
|
-
const question = s.text ? esc(s.text) : "";
|
|
269
|
-
b.style.cssText = base + "top:auto;bottom:16px;left:16px;right:auto;max-width:min(560px,calc(100vw - 32px));border-radius:8px;overflow:hidden;background:#0F9D58;padding:10px 14px;font-size:13px;letter-spacing:.02em;text-align:left;line-height:1.3;pointer-events:none;";
|
|
270
|
-
b.innerHTML =
|
|
271
|
-
'<style>#foldspace-dev-badge .fs-copy{pointer-events:auto;margin-left:12px;padding:4px 10px;border:1px solid rgba(255,255,255,.7);border-radius:4px;background:transparent;color:#fff;font:inherit;font-size:12px;cursor:pointer;letter-spacing:0}' +
|
|
272
|
-
'#foldspace-dev-badge .fs-copy:hover{background:rgba(255,255,255,.15)}</style>' +
|
|
273
|
-
'<b>Ready - your turn.</b> ' +
|
|
274
|
-
(question ? 'Try asking: <span class="fs-q">' + question + '</span><button class="fs-copy" type="button">Copy</button>' : "Open your agent and try it.");
|
|
275
|
-
const btn = b.querySelector(".fs-copy");
|
|
276
|
-
if (btn) btn.addEventListener("click", () => {
|
|
277
|
-
const q = b.querySelector(".fs-q")?.textContent || "";
|
|
278
|
-
const done = () => { btn.textContent = "Copied"; setTimeout(() => { btn.textContent = "Copy"; }, 1500); };
|
|
279
|
-
if (navigator.clipboard?.writeText) navigator.clipboard.writeText(q).then(done, done);
|
|
280
|
-
else { const ta = document.createElement("textarea"); ta.value = q; document.body.appendChild(ta); ta.select(); try { document.execCommand("copy"); } catch (e) {} ta.remove(); done(); }
|
|
281
|
-
});
|
|
282
265
|
} else {
|
|
266
|
+
// "ready" and "label" both draw the small tag: their turn needs no bar -
|
|
267
|
+
// they may type whatever, whenever. Only the wait ever gets a pill.
|
|
283
268
|
b.style.cssText = base + "background:#3247F2;padding:5px 10px;border-bottom-right-radius:4px;";
|
|
284
269
|
b.textContent = LABEL;
|
|
285
270
|
}
|
package/bin/badge.mjs
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* foldspace badge <working|ready|label|off> [--text "<what to show>"]
|
|
4
4
|
*
|
|
5
|
-
* Sets the
|
|
6
|
-
* The agent and the human share that one Chrome window, so the
|
|
7
|
-
*
|
|
5
|
+
* Sets the pill the attach badge draws at the foot of the test window.
|
|
6
|
+
* The agent and the human share that one Chrome window, so the pill says
|
|
7
|
+
* when to wait:
|
|
8
8
|
* working - "Foldspace is building your agent on this page. Please leave
|
|
9
|
-
* this window alone until
|
|
10
|
-
* ready -
|
|
11
|
-
*
|
|
12
|
-
* label -
|
|
9
|
+
* this window alone until the agent says it is ready."
|
|
10
|
+
* ready - the pill goes away, the small corner tag comes back: their
|
|
11
|
+
* turn. No bar for that - they may type whatever, whenever.
|
|
12
|
+
* label - the small corner tag
|
|
13
13
|
* off - remove it
|
|
14
14
|
* The state is kept in the page's sessionStorage, so it survives navigation;
|
|
15
15
|
* attach's badge script redraws within a second. Nothing else on the page is
|
package/package.json
CHANGED
package/src/badge-core.mjs
CHANGED
|
@@ -10,8 +10,8 @@ export function badgePayload(state, text) {
|
|
|
10
10
|
}
|
|
11
11
|
const payload = { state: wanted };
|
|
12
12
|
if (text !== undefined) {
|
|
13
|
-
if (wanted !== "working"
|
|
14
|
-
throw new Error(`--text only applies to working
|
|
13
|
+
if (wanted !== "working") {
|
|
14
|
+
throw new Error(`--text only applies to working (got ${wanted}); their turn needs no bar.`);
|
|
15
15
|
}
|
|
16
16
|
const clean = String(text).replace(/\s+/g, " ").trim();
|
|
17
17
|
if (!clean) throw new Error("--text is empty.");
|
package/src/cli-registry.mjs
CHANGED
|
@@ -321,7 +321,7 @@ export const CLI_COMMANDS = Object.freeze([
|
|
|
321
321
|
name: "badge",
|
|
322
322
|
entry: "badge.mjs",
|
|
323
323
|
group: "verify",
|
|
324
|
-
summary: "Set the
|
|
324
|
+
summary: "Set the pill at the foot of the test window: working (leave it alone), ready (pill away), label or off",
|
|
325
325
|
usage: 'foldspace badge <working|ready|label|off> [--text "<what to show>"]',
|
|
326
326
|
risk: "browser-session",
|
|
327
327
|
environment: "local-chrome",
|
|
@@ -332,18 +332,18 @@ export const CLI_COMMANDS = Object.freeze([
|
|
|
332
332
|
name: "state",
|
|
333
333
|
required: true,
|
|
334
334
|
description:
|
|
335
|
-
"working: the agent is building here, leave the window alone | ready: the
|
|
335
|
+
"working: the agent is building here, leave the window alone | ready: the pill goes away, their turn | label: the small corner tag | off: remove it",
|
|
336
336
|
}),
|
|
337
337
|
],
|
|
338
338
|
options: [
|
|
339
|
-
value("--text", "text", "working
|
|
339
|
+
value("--text", "text", "working only: one extra line under the ask (up to 160 characters)"),
|
|
340
340
|
],
|
|
341
341
|
prerequisites: ["foldspace attach is running (it draws the badge)"],
|
|
342
342
|
effects: [
|
|
343
343
|
"Writes one key to the test window's sessionStorage; touches nothing else on the page",
|
|
344
|
-
"The
|
|
344
|
+
"The pill survives navigation inside the test window",
|
|
345
345
|
],
|
|
346
|
-
next: ["
|
|
346
|
+
next: ["Say in chat whose turn it is and what to try"],
|
|
347
347
|
}),
|
|
348
348
|
Object.freeze({
|
|
349
349
|
name: "deploy",
|