ape-claw 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/package.json +1 -1
- package/src/cli.mjs +23 -3
- package/ui/forge/css/forge.css +61 -0
- package/ui/forge/index.html +61 -0
- package/ui/shared/sidebar-nav.js +2 -1
package/package.json
CHANGED
package/src/cli.mjs
CHANGED
|
@@ -211,15 +211,35 @@ function installApeClawSkill(args) {
|
|
|
211
211
|
};
|
|
212
212
|
}
|
|
213
213
|
|
|
214
|
+
function yamlSafe(val) {
|
|
215
|
+
const s = String(val);
|
|
216
|
+
if (!s) return '""';
|
|
217
|
+
if (/[:{}\[\]#&*!|>'"%@`,\n]/.test(s) || s.startsWith(" ") || s.endsWith(" ")) {
|
|
218
|
+
return `"${s.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
219
|
+
}
|
|
220
|
+
return s;
|
|
221
|
+
}
|
|
222
|
+
|
|
214
223
|
function syncSkillToOpenClaw(cardObj, slug, skillsRoot) {
|
|
215
224
|
const s = String(slug || cardObj?.slug || cardObj?.name || "").toLowerCase().trim()
|
|
216
225
|
.replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
217
226
|
if (!s) return null;
|
|
218
|
-
const
|
|
219
|
-
const
|
|
227
|
+
const rawDoc = String(cardObj?.documentation_md || "").trim();
|
|
228
|
+
const displayName = String(cardObj?.name || s).trim();
|
|
220
229
|
const versionValue = String(cardObj?.version || "1.0.0").trim();
|
|
221
230
|
const descriptionValue = String(cardObj?.description || "").trim();
|
|
222
|
-
const
|
|
231
|
+
const descOneLine = descriptionValue.replace(/\n/g, " ").slice(0, 300);
|
|
232
|
+
|
|
233
|
+
const openclawFrontmatter = `---\nname: ${s}\nversion: ${yamlSafe(versionValue)}\ndescription: ${yamlSafe(descOneLine)}\n---\n`;
|
|
234
|
+
|
|
235
|
+
let content;
|
|
236
|
+
if (rawDoc) {
|
|
237
|
+
// Strip existing frontmatter from documentation_md and prepend OpenClaw-compatible one
|
|
238
|
+
const stripped = rawDoc.replace(/^---[\s\S]*?---\s*/, "").trim();
|
|
239
|
+
content = openclawFrontmatter + "\n" + stripped;
|
|
240
|
+
} else {
|
|
241
|
+
content = openclawFrontmatter + `\n# ${displayName}\n\n${descriptionValue}\n`;
|
|
242
|
+
}
|
|
223
243
|
|
|
224
244
|
const skillDir = path.join(skillsRoot, s);
|
|
225
245
|
fs.mkdirSync(skillDir, { recursive: true });
|
package/ui/forge/css/forge.css
CHANGED
|
@@ -431,6 +431,67 @@ a{color:var(--neon-cyan);text-decoration:none}
|
|
|
431
431
|
@keyframes forgeToastIn{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}
|
|
432
432
|
@keyframes forgeToastOut{from{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(-12px)}}
|
|
433
433
|
|
|
434
|
+
/* ── Offline Gate ───────────────────────────────────────── */
|
|
435
|
+
.forge-offline-gate{
|
|
436
|
+
position:fixed;inset:0;z-index:9999;display:flex;align-items:center;justify-content:center;
|
|
437
|
+
background:var(--bg);padding:24px;
|
|
438
|
+
}
|
|
439
|
+
.forge-offline-card{
|
|
440
|
+
max-width:560px;width:100%;background:var(--surface);border:1px solid var(--border);
|
|
441
|
+
border-radius:6px;padding:40px 36px;text-align:center;position:relative;
|
|
442
|
+
box-shadow:0 0 80px rgba(207,255,4,.06),var(--panel-shadow);
|
|
443
|
+
}
|
|
444
|
+
.forge-offline-icon{font-size:3.5rem;margin-bottom:12px;filter:drop-shadow(0 0 18px rgba(207,255,4,.35))}
|
|
445
|
+
.forge-offline-title{
|
|
446
|
+
font-family:var(--font-display);font-weight:900;font-size:1.6rem;letter-spacing:.06em;
|
|
447
|
+
color:var(--accent);text-transform:uppercase;margin-bottom:6px;
|
|
448
|
+
}
|
|
449
|
+
.forge-offline-sub{color:var(--dim);font-size:.85rem;margin-bottom:0}
|
|
450
|
+
.forge-offline-divider{
|
|
451
|
+
height:1px;background:linear-gradient(90deg,transparent,var(--border),transparent);
|
|
452
|
+
margin:20px 0;
|
|
453
|
+
}
|
|
454
|
+
.forge-offline-desc{color:var(--text);font-size:.82rem;line-height:1.65;text-align:left;margin-bottom:4px}
|
|
455
|
+
.forge-offline-steps{text-align:left;margin:18px 0}
|
|
456
|
+
.forge-offline-step{
|
|
457
|
+
display:flex;gap:14px;align-items:flex-start;padding:12px 0;
|
|
458
|
+
border-bottom:1px solid rgba(255,255,255,.05);
|
|
459
|
+
}
|
|
460
|
+
.forge-offline-step:last-child{border-bottom:none}
|
|
461
|
+
.forge-offline-step-num{
|
|
462
|
+
flex-shrink:0;width:26px;height:26px;display:flex;align-items:center;justify-content:center;
|
|
463
|
+
border-radius:50%;background:rgba(207,255,4,.12);border:1px solid var(--border);
|
|
464
|
+
color:var(--accent);font-weight:800;font-size:.7rem;font-family:var(--font-mono);
|
|
465
|
+
}
|
|
466
|
+
.forge-offline-step strong{display:block;color:var(--text);font-size:.8rem;margin-bottom:3px}
|
|
467
|
+
.forge-offline-step code{
|
|
468
|
+
display:block;font-family:var(--font-mono);font-size:.72rem;color:var(--neon-cyan);
|
|
469
|
+
background:rgba(0,0,0,.5);border:1px solid rgba(99,215,255,.15);border-radius:3px;
|
|
470
|
+
padding:6px 10px;margin-top:4px;word-break:break-all;
|
|
471
|
+
}
|
|
472
|
+
.forge-offline-hint{display:block;font-size:.68rem;color:var(--dim);margin-top:3px}
|
|
473
|
+
.forge-offline-hint code{display:inline;padding:1px 5px;margin:0;font-size:.68rem}
|
|
474
|
+
.forge-offline-note{font-size:.72rem;color:var(--dim);line-height:1.7;text-align:center}
|
|
475
|
+
.forge-offline-note code{
|
|
476
|
+
font-family:var(--font-mono);font-size:.68rem;color:var(--neon-green);
|
|
477
|
+
background:rgba(0,255,0,.06);padding:2px 6px;border-radius:2px;
|
|
478
|
+
}
|
|
479
|
+
.forge-offline-dim{color:rgba(255,255,255,.3)}
|
|
480
|
+
.forge-offline-links{display:flex;gap:10px;justify-content:center;margin-top:20px}
|
|
481
|
+
.forge-offline-btn{
|
|
482
|
+
display:inline-flex;align-items:center;padding:9px 22px;border-radius:3px;
|
|
483
|
+
font-family:var(--font-display);font-weight:700;font-size:.78rem;letter-spacing:.04em;
|
|
484
|
+
text-transform:uppercase;text-decoration:none;transition:all .2s;
|
|
485
|
+
background:var(--accent);color:#0c0c0c;border:1px solid var(--accent);
|
|
486
|
+
}
|
|
487
|
+
.forge-offline-btn:hover{background:#e2ff40;box-shadow:0 0 16px rgba(207,255,4,.3)}
|
|
488
|
+
.forge-offline-btn-secondary{
|
|
489
|
+
background:transparent;color:var(--text);border-color:var(--border);
|
|
490
|
+
}
|
|
491
|
+
.forge-offline-btn-secondary:hover{
|
|
492
|
+
background:rgba(207,255,4,.08);color:var(--accent);border-color:var(--accent);
|
|
493
|
+
}
|
|
494
|
+
|
|
434
495
|
/* ── Responsive ─────────────────────────────────────────── */
|
|
435
496
|
@media(max-width:1199px){
|
|
436
497
|
.forge-bottom{grid-template-columns:1fr;max-height:none}
|
package/ui/forge/index.html
CHANGED
|
@@ -169,6 +169,67 @@
|
|
|
169
169
|
</footer>
|
|
170
170
|
</div>
|
|
171
171
|
|
|
172
|
+
<!-- Forge requires a local server to discover installed skills -->
|
|
173
|
+
<div class="forge-offline-gate" id="forgeOfflineGate" style="display:none">
|
|
174
|
+
<div class="forge-offline-card">
|
|
175
|
+
<div class="forge-offline-icon">🤖</div>
|
|
176
|
+
<h2 class="forge-offline-title">ClawBot Forge</h2>
|
|
177
|
+
<p class="forge-offline-sub">Your 3D agent — shaped by the skills you install</p>
|
|
178
|
+
<div class="forge-offline-divider"></div>
|
|
179
|
+
<p class="forge-offline-desc">
|
|
180
|
+
The Forge renders <strong>your</strong> installed skills as attachments on a 3D robot.
|
|
181
|
+
It discovers skills from your local Cursor & OpenClaw directories, so it must be
|
|
182
|
+
hosted on your machine.
|
|
183
|
+
</p>
|
|
184
|
+
<div class="forge-offline-steps">
|
|
185
|
+
<div class="forge-offline-step">
|
|
186
|
+
<span class="forge-offline-step-num">1</span>
|
|
187
|
+
<div>
|
|
188
|
+
<strong>Install ApeClaw + skills</strong>
|
|
189
|
+
<code>npx ape-claw skill install --starter-pack</code>
|
|
190
|
+
</div>
|
|
191
|
+
</div>
|
|
192
|
+
<div class="forge-offline-step">
|
|
193
|
+
<span class="forge-offline-step-num">2</span>
|
|
194
|
+
<div>
|
|
195
|
+
<strong>Clone the repo & start the server</strong>
|
|
196
|
+
<code>git clone https://github.com/simplefarmer69/ape-claw.git && cd ape-claw && npm install && npm run start:ui</code>
|
|
197
|
+
</div>
|
|
198
|
+
</div>
|
|
199
|
+
<div class="forge-offline-step">
|
|
200
|
+
<span class="forge-offline-step-num">3</span>
|
|
201
|
+
<div>
|
|
202
|
+
<strong>Open the Forge</strong>
|
|
203
|
+
<code>http://localhost:8799/forge</code>
|
|
204
|
+
<span class="forge-offline-hint">Your installed skills appear as 3D attachments on the robot automatically</span>
|
|
205
|
+
</div>
|
|
206
|
+
</div>
|
|
207
|
+
</div>
|
|
208
|
+
<div class="forge-offline-divider"></div>
|
|
209
|
+
<p class="forge-offline-note">
|
|
210
|
+
The Forge reads skills installed via <code>npx ape-claw skill install</code>.<br>
|
|
211
|
+
Skills are synced to <code>~/.cursor/skills/</code> and <code>~/.openclaw/workspace/skills/</code> automatically.
|
|
212
|
+
</p>
|
|
213
|
+
<div class="forge-offline-links">
|
|
214
|
+
<a class="forge-offline-btn" href="/skills">Browse Skills</a>
|
|
215
|
+
<a class="forge-offline-btn forge-offline-btn-secondary" href="https://github.com/simplefarmer69/ape-claw" target="_blank" rel="noopener">GitHub</a>
|
|
216
|
+
</div>
|
|
217
|
+
</div>
|
|
218
|
+
</div>
|
|
219
|
+
|
|
220
|
+
<script>
|
|
221
|
+
(async function detectLocal() {
|
|
222
|
+
try {
|
|
223
|
+
const r = await fetch("/api/health", { signal: AbortSignal.timeout(4000) });
|
|
224
|
+
if (r.ok) return; // local server running — load the forge normally
|
|
225
|
+
} catch {}
|
|
226
|
+
// Not local — show the offline gate and hide the forge app
|
|
227
|
+
document.getElementById("forgeOfflineGate").style.display = "";
|
|
228
|
+
const app = document.querySelector(".forge-app");
|
|
229
|
+
if (app) app.style.display = "none";
|
|
230
|
+
})();
|
|
231
|
+
</script>
|
|
232
|
+
|
|
172
233
|
<script type="importmap">
|
|
173
234
|
{
|
|
174
235
|
"imports": {
|
package/ui/shared/sidebar-nav.js
CHANGED
|
@@ -53,11 +53,12 @@
|
|
|
53
53
|
var active = !l.external && isActive(l.href, cur);
|
|
54
54
|
var attrs = active ? ' aria-current="page"' : "";
|
|
55
55
|
if (l.external) attrs += ' target="_blank" rel="noopener"';
|
|
56
|
+
var badge = l.external ? "EXT" : (l.icon === "forge" ? "LOCAL" : "");
|
|
56
57
|
navHtml +=
|
|
57
58
|
'<a class="sb-link" href="' + String(l.href) + '" data-tip="' + String(l.label) + '"' + attrs + ">" +
|
|
58
59
|
iconSvg(l.icon) +
|
|
59
60
|
'<span class="sb-text">' + String(l.label) + "</span>" +
|
|
60
|
-
|
|
61
|
+
'<span class="sb-sub">' + badge + '</span>' +
|
|
61
62
|
"</a>";
|
|
62
63
|
}
|
|
63
64
|
|