@easysociable/cli 0.1.3 → 0.1.5
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 +13 -10
- package/content-engine/scripts/starter.mjs +3 -1
- package/content-engine/scripts/workbench.mjs +13 -8
- package/content-engine/starter/CLAUDE.md +217 -128
- package/content-engine/starter/engine.json +3 -0
- package/content-engine/starter/needs/README.md +38 -0
- package/content-engine/starter/needs/_index.md +31 -0
- package/content-engine/starter/needs/_template.md +24 -0
- package/content-engine/starter/needs/entries/README.md +5 -0
- package/content-engine/starter/products/README.md +38 -0
- package/content-engine/starter/products/_index.md +24 -0
- package/content-engine/starter/products/_template.md +56 -0
- package/content-engine/starter/products/entries/P-001-easysociable.md +150 -0
- package/content-engine/starter/profiles/_index.md +6 -3
- package/content-engine/starter/profiles/default/README.md +4 -1
- package/content-engine/starter/profiles/default/boundaries.md +14 -0
- package/content-engine/starter/profiles/default/expression.md +18 -0
- package/content-engine/starter/profiles/default/lanes.md +12 -0
- package/content-engine/starter/profiles/default/stories.md +15 -0
- package/content-engine/starter/profiles/default/voice.md +14 -0
- package/content-engine/starter/recommendations/README.md +21 -0
- package/content-engine/starter/recommendations/_index.md +21 -0
- package/content-engine/starter/recommendations/_template.md +44 -0
- package/content-engine/starter/runs/_template/brief.md +1 -1
- package/content-engine/starter/runs/_template/pack.md +15 -7
- package/content-engine/starter/runs/_template/packet.md +6 -0
- package/content-engine/starter/swipe/_template.md +3 -1
- package/content-engine/starter/topics/README.md +4 -8
- package/content-engine/starter/topics/_index.md +12 -5
- package/content-engine/starter/topics/_template-item.md +64 -51
- package/content-engine/starter/topics/scoring.md +55 -4
- package/content-engine/workbench/build.py +315 -97
- package/content-engine/workbench/serve.py +0 -0
- package/content-engine/workbench/template.html +172 -94
- package/dist/easysociable.js +191 -133
- package/dist/easysociable.js.map +1 -1
- package/package.json +13 -14
- package/skills/ONBOARDING.md +14 -15
- package/skills/easysociable-content/SKILL.md +100 -19
- package/skills/easysociable-content/workflows/INTERVIEW.md +70 -0
- package/skills/easysociable-content/workflows/NEEDS.md +82 -0
- package/skills/easysociable-slideshow/SKILL.md +79 -45
- package/skills/easysociable-slideshow/references/ARC.md +44 -0
- package/skills/easysociable-slideshow/references/CONTENT_PACK.md +34 -6
- package/skills/easysociable-slideshow/workflows/CREATE_RUN.md +24 -5
- package/skills/easysociable-slideshow/workflows/OUT_OF_SCOPE.md +3 -0
- package/skills/easysociable-template/SKILL.md +13 -16
- package/skills/easysociable-template/references/CATALOG_METADATA.md +21 -18
- package/skills/easysociable-template/scripts/generate-theme-from-hex.mjs +0 -0
- package/skills/easysociable-template/workflows/FILL_AND_RENDER.md +4 -83
- package/skills/easysociable-template/workflows/OUT_OF_SCOPE.md +3 -2
- package/content-engine/starter/discovery/README.md +0 -18
- package/content-engine/starter/discovery/_index.md +0 -27
- package/content-engine/starter/discovery/_template.md +0 -41
- package/content-engine/starter/topics/WATCHLIST.md +0 -65
- package/content-engine/starter/topics/watchlists/README.md +0 -10
- package/content-engine/starter/topics/watchlists/_shared.md +0 -14
- package/content-engine/starter/topics/watchlists/default.md +0 -6
package/dist/easysociable.js
CHANGED
|
@@ -15351,6 +15351,10 @@ function parseSlideshowRunSummaryList(payload) {
|
|
|
15351
15351
|
assertNoPrivateTemplateFields(payload);
|
|
15352
15352
|
return parseDataEnvelope(payload, external_exports.array(slideshowRunSummarySchema));
|
|
15353
15353
|
}
|
|
15354
|
+
function parseSlideshowRunSummary(payload) {
|
|
15355
|
+
assertNoPrivateTemplateFields(payload);
|
|
15356
|
+
return parseDataEnvelope(payload, slideshowRunSummarySchema);
|
|
15357
|
+
}
|
|
15354
15358
|
function parseBrand(payload) {
|
|
15355
15359
|
return parseDataEnvelope(payload, brandSchema);
|
|
15356
15360
|
}
|
|
@@ -15538,7 +15542,10 @@ var init_src = __esm({
|
|
|
15538
15542
|
notFor: external_exports.array(external_exports.string()).optional(),
|
|
15539
15543
|
locale: external_exports.enum(["zh-CN", "en", "bilingual"]).optional(),
|
|
15540
15544
|
capacity: external_exports.record(external_exports.string(), external_exports.unknown()).optional(),
|
|
15541
|
-
previewImageUrl: external_exports.string().url().optional()
|
|
15545
|
+
previewImageUrl: external_exports.string().url().optional(),
|
|
15546
|
+
/** Layout Family id — catalog UIs group variants by this (ADR-0033). */
|
|
15547
|
+
familyId: external_exports.string().optional(),
|
|
15548
|
+
familyRole: external_exports.enum(["master", "variant"]).optional()
|
|
15542
15549
|
}).strict();
|
|
15543
15550
|
publicTemplateSlotTypeSchema = external_exports.enum(["text", "number", "image"]);
|
|
15544
15551
|
publicTemplateSlotSchema = external_exports.object({
|
|
@@ -16288,7 +16295,7 @@ function isRetryableStatus(status) {
|
|
|
16288
16295
|
return status === 429 || status === 502 || status === 503 || status === 504;
|
|
16289
16296
|
}
|
|
16290
16297
|
function sleep(ms) {
|
|
16291
|
-
return new Promise((
|
|
16298
|
+
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
16292
16299
|
}
|
|
16293
16300
|
var TemplateGatewayError, TemplateGatewayClient;
|
|
16294
16301
|
var init_client = __esm({
|
|
@@ -16569,11 +16576,11 @@ var init_client = __esm({
|
|
|
16569
16576
|
this.throwIfError(response.status, response.json);
|
|
16570
16577
|
return parseSlideshowRun(response.json);
|
|
16571
16578
|
}
|
|
16579
|
+
/** Permanently delete a Slideshow Run (ADR-0034 hard delete). */
|
|
16572
16580
|
async trashSlideshowRun(runId) {
|
|
16573
16581
|
const response = await this.request("DELETE", `/v1/slideshow/runs/${encodeURIComponent(runId)}`);
|
|
16574
16582
|
this.throwIfError(response.status, response.json);
|
|
16575
|
-
|
|
16576
|
-
return rows[0];
|
|
16583
|
+
return parseSlideshowRunSummary(response.json);
|
|
16577
16584
|
}
|
|
16578
16585
|
async renderSlideshowRun(runId, body) {
|
|
16579
16586
|
const input = renderSlideshowRunInputSchema.parse(body ?? {});
|
|
@@ -23452,7 +23459,7 @@ var init_protocol = __esm({
|
|
|
23452
23459
|
return;
|
|
23453
23460
|
}
|
|
23454
23461
|
const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
|
|
23455
|
-
await new Promise((
|
|
23462
|
+
await new Promise((resolve3) => setTimeout(resolve3, pollInterval));
|
|
23456
23463
|
options?.signal?.throwIfAborted();
|
|
23457
23464
|
}
|
|
23458
23465
|
} catch (error52) {
|
|
@@ -23469,7 +23476,7 @@ var init_protocol = __esm({
|
|
|
23469
23476
|
*/
|
|
23470
23477
|
request(request, resultSchema, options) {
|
|
23471
23478
|
const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
|
|
23472
|
-
return new Promise((
|
|
23479
|
+
return new Promise((resolve3, reject) => {
|
|
23473
23480
|
const earlyReject = (error52) => {
|
|
23474
23481
|
reject(error52);
|
|
23475
23482
|
};
|
|
@@ -23547,7 +23554,7 @@ var init_protocol = __esm({
|
|
|
23547
23554
|
if (!parseResult.success) {
|
|
23548
23555
|
reject(parseResult.error);
|
|
23549
23556
|
} else {
|
|
23550
|
-
|
|
23557
|
+
resolve3(parseResult.data);
|
|
23551
23558
|
}
|
|
23552
23559
|
} catch (error52) {
|
|
23553
23560
|
reject(error52);
|
|
@@ -23808,12 +23815,12 @@ var init_protocol = __esm({
|
|
|
23808
23815
|
}
|
|
23809
23816
|
} catch {
|
|
23810
23817
|
}
|
|
23811
|
-
return new Promise((
|
|
23818
|
+
return new Promise((resolve3, reject) => {
|
|
23812
23819
|
if (signal.aborted) {
|
|
23813
23820
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
23814
23821
|
return;
|
|
23815
23822
|
}
|
|
23816
|
-
const timeoutId = setTimeout(
|
|
23823
|
+
const timeoutId = setTimeout(resolve3, interval);
|
|
23817
23824
|
signal.addEventListener("abort", () => {
|
|
23818
23825
|
clearTimeout(timeoutId);
|
|
23819
23826
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
@@ -26840,7 +26847,7 @@ var require_compile = __commonJS({
|
|
|
26840
26847
|
const schOrFunc = root.refs[ref];
|
|
26841
26848
|
if (schOrFunc)
|
|
26842
26849
|
return schOrFunc;
|
|
26843
|
-
let _sch =
|
|
26850
|
+
let _sch = resolve3.call(this, root, ref);
|
|
26844
26851
|
if (_sch === void 0) {
|
|
26845
26852
|
const schema = (_a3 = root.localRefs) === null || _a3 === void 0 ? void 0 : _a3[ref];
|
|
26846
26853
|
const { schemaId } = this.opts;
|
|
@@ -26867,7 +26874,7 @@ var require_compile = __commonJS({
|
|
|
26867
26874
|
function sameSchemaEnv(s1, s2) {
|
|
26868
26875
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
26869
26876
|
}
|
|
26870
|
-
function
|
|
26877
|
+
function resolve3(root, ref) {
|
|
26871
26878
|
let sch;
|
|
26872
26879
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
26873
26880
|
ref = sch;
|
|
@@ -27442,7 +27449,7 @@ var require_fast_uri = __commonJS({
|
|
|
27442
27449
|
}
|
|
27443
27450
|
return uri;
|
|
27444
27451
|
}
|
|
27445
|
-
function
|
|
27452
|
+
function resolve3(baseURI, relativeURI, options) {
|
|
27446
27453
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
27447
27454
|
const resolved = resolveComponent(parse5(baseURI, schemelessOptions), parse5(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
27448
27455
|
schemelessOptions.skipEscape = true;
|
|
@@ -27669,7 +27676,7 @@ var require_fast_uri = __commonJS({
|
|
|
27669
27676
|
var fastUri = {
|
|
27670
27677
|
SCHEMES,
|
|
27671
27678
|
normalize,
|
|
27672
|
-
resolve:
|
|
27679
|
+
resolve: resolve3,
|
|
27673
27680
|
resolveComponent,
|
|
27674
27681
|
equal,
|
|
27675
27682
|
serialize,
|
|
@@ -31568,12 +31575,12 @@ var init_stdio2 = __esm({
|
|
|
31568
31575
|
this.onclose?.();
|
|
31569
31576
|
}
|
|
31570
31577
|
send(message) {
|
|
31571
|
-
return new Promise((
|
|
31578
|
+
return new Promise((resolve3) => {
|
|
31572
31579
|
const json2 = serializeMessage(message);
|
|
31573
31580
|
if (this._stdout.write(json2)) {
|
|
31574
|
-
|
|
31581
|
+
resolve3();
|
|
31575
31582
|
} else {
|
|
31576
|
-
this._stdout.once("drain",
|
|
31583
|
+
this._stdout.once("drain", resolve3);
|
|
31577
31584
|
}
|
|
31578
31585
|
});
|
|
31579
31586
|
}
|
|
@@ -31644,8 +31651,8 @@ async function serveStdioMcp(options) {
|
|
|
31644
31651
|
await waitForStdioServerClose(server, process.stdin);
|
|
31645
31652
|
}
|
|
31646
31653
|
async function waitForStdioServerClose(server, stdin = process.stdin) {
|
|
31647
|
-
await new Promise((
|
|
31648
|
-
server.onclose = () =>
|
|
31654
|
+
await new Promise((resolve3) => {
|
|
31655
|
+
server.onclose = () => resolve3();
|
|
31649
31656
|
if (stdin.readableEnded || stdin.destroyed) {
|
|
31650
31657
|
void server.close().catch(() => void 0);
|
|
31651
31658
|
return;
|
|
@@ -31974,7 +31981,7 @@ var init_src4 = __esm({
|
|
|
31974
31981
|
{
|
|
31975
31982
|
name: "create_render_job",
|
|
31976
31983
|
title: "Create render job",
|
|
31977
|
-
description: "
|
|
31984
|
+
description: "Retired as a paid delivery path. PNG packs come from Studio Download. Gateway returns HEADLESS_RENDER_DISABLED. Kept for compatibility; do not use for customer PNG delivery. Historic fill-slots shape: templateId + slots + outputFormats (ADR-0021).",
|
|
31978
31985
|
effect: "local-write-job",
|
|
31979
31986
|
inputSchema: {
|
|
31980
31987
|
type: "object",
|
|
@@ -32275,8 +32282,8 @@ var init_src5 = __esm({
|
|
|
32275
32282
|
{ name: "update_run", title: "Update slideshow run", description: "Edit page-instance slots/layout/style/decorations or presentation preference with optimistic revision.", effect: "local-write-job", inputSchema: { ...objectSchema, properties: { runId: { type: "string" }, pack: { type: "object" }, brandId: { type: "string" }, brandProfileId: { type: "string" }, contentSlug: { type: "string" }, baseRevision: { type: "integer", minimum: 1 }, pageIndex: { type: "integer", minimum: 0 }, slots: { type: "object" }, layout: { type: "object" }, style: { type: "object" }, decorations: { type: "array" } }, required: ["runId"] }, outputSchema: objectSchema },
|
|
32276
32283
|
{ name: "archive_run", title: "Archive slideshow run", description: "Hide a Run from default lists without deleting it.", effect: "local-write-job", inputSchema: { ...objectSchema, properties: { runId: { type: "string" } }, required: ["runId"] }, outputSchema: objectSchema },
|
|
32277
32284
|
{ name: "restore_run", title: "Restore slideshow run", description: "Restore an archived or trashed Run.", effect: "local-write-job", inputSchema: { ...objectSchema, properties: { runId: { type: "string" } }, required: ["runId"] }, outputSchema: objectSchema },
|
|
32278
|
-
{ name: "trash_run", title: "
|
|
32279
|
-
{ name: "render_run", title: "Render slideshow run", description: "
|
|
32285
|
+
{ name: "trash_run", title: "Delete slideshow run", description: "Permanently delete a Slideshow Run (hard delete; not recoverable).", effect: "explicit-approval", inputSchema: { ...objectSchema, properties: { runId: { type: "string" } }, required: ["runId"] }, outputSchema: objectSchema },
|
|
32286
|
+
{ name: "render_run", title: "Render slideshow run", description: "Retired. PNG packs come from Studio Download in the browser, not hosted render jobs.", effect: "local-write-job", inputSchema: { ...objectSchema, properties: { runId: { type: "string" }, idempotencyKey: { type: "string", minLength: 1, maxLength: 128 } }, required: ["runId", "idempotencyKey"] }, outputSchema: objectSchema }
|
|
32280
32287
|
];
|
|
32281
32288
|
slideshowResourceTemplates = [
|
|
32282
32289
|
{ uriTemplate: "slideshow://runs/{runId}", name: "Slideshow Run", description: "Owner-scoped Run JSON snapshot", mimeType: "application/json" }
|
|
@@ -32311,7 +32318,7 @@ var init_src5 = __esm({
|
|
|
32311
32318
|
case "trash_run":
|
|
32312
32319
|
return { ok: true, data: await this.client.trashSlideshowRun(String(args.runId)), meta: m };
|
|
32313
32320
|
case "render_run":
|
|
32314
|
-
return { ok:
|
|
32321
|
+
return { ok: false, error: { code: "HEADLESS_RENDER_DISABLED", message: "PNG packs come from Studio Download, not CLI/MCP hosted jobs", retryable: false, suggestedAction: "Open the Slideshow in Studio and click Download" }, meta: m };
|
|
32315
32322
|
default:
|
|
32316
32323
|
return { ok: false, error: { code: "UNKNOWN_TOOL", message: `Unknown tool: ${toolName}`, retryable: false }, meta: m };
|
|
32317
32324
|
}
|
|
@@ -32343,13 +32350,20 @@ async function serveUnifiedStdioMcp(client) {
|
|
|
32343
32350
|
resourceTemplates: unifiedResourceTemplates
|
|
32344
32351
|
}, { backendName: "gateway" });
|
|
32345
32352
|
}
|
|
32346
|
-
var removedTools, templateNames, slideshowNames, brandTools, rename, templateTools, slideshowTools, imageTools, unifiedToolRegistry, unifiedResourceTemplates, UnifiedMcpBackend;
|
|
32353
|
+
var HEADLESS_PNG_DELIVERY, HEADLESS_TOOLS, removedTools, templateNames, slideshowNames, brandTools, rename, templateTools, slideshowTools, imageTools, unifiedToolRegistry, unifiedResourceTemplates, UnifiedMcpBackend;
|
|
32347
32354
|
var init_src6 = __esm({
|
|
32348
32355
|
"../../packages/mcp-server/src/index.ts"() {
|
|
32349
32356
|
"use strict";
|
|
32350
32357
|
init_src3();
|
|
32351
32358
|
init_src4();
|
|
32352
32359
|
init_src5();
|
|
32360
|
+
HEADLESS_PNG_DELIVERY = {
|
|
32361
|
+
code: "HEADLESS_RENDER_DISABLED",
|
|
32362
|
+
message: "PNG packs come from Studio Download, not CLI/MCP hosted jobs",
|
|
32363
|
+
retryable: false,
|
|
32364
|
+
suggestedAction: "Open the Slideshow in Studio and click Download"
|
|
32365
|
+
};
|
|
32366
|
+
HEADLESS_TOOLS = /* @__PURE__ */ new Set(["create_template_render_job", "render_slideshow_run"]);
|
|
32353
32367
|
removedTools = /* @__PURE__ */ new Set(["publish_run", "unpublish_run"]);
|
|
32354
32368
|
templateNames = {
|
|
32355
32369
|
create_draft: "create_template_draft",
|
|
@@ -32403,6 +32417,13 @@ var init_src6 = __esm({
|
|
|
32403
32417
|
this.slideshow = new SlideshowMcpBackend(client);
|
|
32404
32418
|
}
|
|
32405
32419
|
invoke(toolName, args) {
|
|
32420
|
+
if (HEADLESS_TOOLS.has(toolName)) {
|
|
32421
|
+
return Promise.resolve({
|
|
32422
|
+
ok: false,
|
|
32423
|
+
error: { ...HEADLESS_PNG_DELIVERY },
|
|
32424
|
+
meta: { requestId: `mcp_${Date.now().toString(36)}`, runtimeVersion: "0.0.0", schemaVersion: 1, toolContractVersion: "2026-09-04" }
|
|
32425
|
+
});
|
|
32426
|
+
}
|
|
32406
32427
|
const templateTool = templateTools.find((tool) => tool.name === toolName);
|
|
32407
32428
|
if (templateTool) return this.template.invoke(Object.entries(templateNames).find(([, name]) => name === toolName)?.[0] ?? toolName, args);
|
|
32408
32429
|
const slideshowTool = slideshowTools.find((tool) => tool.name === toolName);
|
|
@@ -32486,11 +32507,10 @@ var init_v1_mcp = __esm({
|
|
|
32486
32507
|
|
|
32487
32508
|
// src/v1-cli.ts
|
|
32488
32509
|
init_src2();
|
|
32489
|
-
import { cp,
|
|
32510
|
+
import { cp, readFile, writeFile, mkdir, chmod, copyFile } from "fs/promises";
|
|
32490
32511
|
import { existsSync as existsSync4, readFileSync as readFileSync3, statSync as statSync2 } from "fs";
|
|
32491
|
-
import {
|
|
32492
|
-
import {
|
|
32493
|
-
import { join as join4 } from "path";
|
|
32512
|
+
import { homedir as homedir3 } from "os";
|
|
32513
|
+
import { join as join4, resolve as resolve2 } from "path";
|
|
32494
32514
|
import { Command } from "commander";
|
|
32495
32515
|
|
|
32496
32516
|
// src/runtime/mcp-hosts.ts
|
|
@@ -32688,7 +32708,9 @@ function engineJson() {
|
|
|
32688
32708
|
runs: "runs",
|
|
32689
32709
|
exports: "exports",
|
|
32690
32710
|
topics: "topics",
|
|
32691
|
-
|
|
32711
|
+
needs: "needs",
|
|
32712
|
+
products: "products",
|
|
32713
|
+
recommendations: "recommendations",
|
|
32692
32714
|
swipe: "swipe",
|
|
32693
32715
|
profiles: "profiles",
|
|
32694
32716
|
inbox: "inbox",
|
|
@@ -32729,7 +32751,95 @@ function inventory(engine, moduleUrl) {
|
|
|
32729
32751
|
starterComplete: missing.length === 0
|
|
32730
32752
|
};
|
|
32731
32753
|
}
|
|
32732
|
-
function
|
|
32754
|
+
function tableCell(md, field) {
|
|
32755
|
+
const escaped = field.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
32756
|
+
const match = md.match(new RegExp(`^\\|\\s*(?:\\*\\*)?${escaped}(?:\\*\\*)?\\s*\\|\\s*([^|]*?)\\|`, "im"));
|
|
32757
|
+
return match ? match[1].trim() : null;
|
|
32758
|
+
}
|
|
32759
|
+
function isFilledCell(value) {
|
|
32760
|
+
if (value == null)
|
|
32761
|
+
return false;
|
|
32762
|
+
const text = value.trim();
|
|
32763
|
+
return text.length > 0 && !/\(fill\)/i.test(text);
|
|
32764
|
+
}
|
|
32765
|
+
function headingSection(md, title) {
|
|
32766
|
+
const escaped = title.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
32767
|
+
const match = md.match(new RegExp(`^##\\s+${escaped}\\s*$`, "im"));
|
|
32768
|
+
if (!match || match.index == null)
|
|
32769
|
+
return null;
|
|
32770
|
+
const rest = md.slice(match.index + match[0].length);
|
|
32771
|
+
const next = rest.search(/^##\s+/m);
|
|
32772
|
+
return (next < 0 ? rest : rest.slice(0, next)).trim();
|
|
32773
|
+
}
|
|
32774
|
+
function isFilledSection(body) {
|
|
32775
|
+
if (body == null)
|
|
32776
|
+
return false;
|
|
32777
|
+
const cleaned = body.replace(/\(fill\)/gi, "").replace(/^[-*]\s*$/gm, "").replace(/^\d+\.\s*$/gm, "").trim();
|
|
32778
|
+
return cleaned.length > 0;
|
|
32779
|
+
}
|
|
32780
|
+
function activeProfileId(engine) {
|
|
32781
|
+
const path = join3(engine, "accounts", "_index.md");
|
|
32782
|
+
if (!existsSync3(path))
|
|
32783
|
+
return null;
|
|
32784
|
+
for (const line of readFileSync2(path, "utf8").split("\n")) {
|
|
32785
|
+
if (!line.startsWith("|"))
|
|
32786
|
+
continue;
|
|
32787
|
+
const cells = line.split("|").slice(1, -1).map((cell) => cell.trim());
|
|
32788
|
+
if (cells.length < 7)
|
|
32789
|
+
continue;
|
|
32790
|
+
if (/^-+$/.test(cells[0]) || /^handle$/i.test(cells[0]) || /^column$/i.test(cells[0]))
|
|
32791
|
+
continue;
|
|
32792
|
+
if (cells[6].toLowerCase() === "active" && cells[1])
|
|
32793
|
+
return cells[1];
|
|
32794
|
+
}
|
|
32795
|
+
return null;
|
|
32796
|
+
}
|
|
32797
|
+
function countNeedIds(md) {
|
|
32798
|
+
let count = 0;
|
|
32799
|
+
for (const line of md.split("\n")) {
|
|
32800
|
+
if (/^\|\s*N-\d{8}-\d+/.test(line))
|
|
32801
|
+
count += 1;
|
|
32802
|
+
}
|
|
32803
|
+
return count;
|
|
32804
|
+
}
|
|
32805
|
+
function checkKnowledge(engine) {
|
|
32806
|
+
const missing = [];
|
|
32807
|
+
const profileId = activeProfileId(engine);
|
|
32808
|
+
if (!profileId)
|
|
32809
|
+
missing.push("accounts/_index.md");
|
|
32810
|
+
const profile = profileId || "default";
|
|
32811
|
+
const voiceRel = `profiles/${profile}/voice.md`;
|
|
32812
|
+
const voicePath = join3(engine, voiceRel);
|
|
32813
|
+
if (!existsSync3(voicePath)) {
|
|
32814
|
+
missing.push(voiceRel);
|
|
32815
|
+
} else {
|
|
32816
|
+
const voice = readFileSync2(voicePath, "utf8");
|
|
32817
|
+
for (const field of ["Role", "What I build", "Point of view"]) {
|
|
32818
|
+
if (!isFilledCell(tableCell(voice, field))) {
|
|
32819
|
+
missing.push(voiceRel);
|
|
32820
|
+
break;
|
|
32821
|
+
}
|
|
32822
|
+
}
|
|
32823
|
+
}
|
|
32824
|
+
const boundariesRel = `profiles/${profile}/boundaries.md`;
|
|
32825
|
+
const boundariesPath = join3(engine, boundariesRel);
|
|
32826
|
+
if (!existsSync3(boundariesPath)) {
|
|
32827
|
+
missing.push(boundariesRel);
|
|
32828
|
+
} else {
|
|
32829
|
+
const boundaries = readFileSync2(boundariesPath, "utf8");
|
|
32830
|
+
if (!isFilledSection(headingSection(boundaries, "Not covering")) || !isFilledSection(headingSection(boundaries, "Never claim")))
|
|
32831
|
+
missing.push(boundariesRel);
|
|
32832
|
+
}
|
|
32833
|
+
const needsDir = join3(engine, "needs");
|
|
32834
|
+
if (isDir(needsDir)) {
|
|
32835
|
+
const needsRel = "needs/_index.md";
|
|
32836
|
+
const needsPath = join3(engine, needsRel);
|
|
32837
|
+
if (!existsSync3(needsPath) || countNeedIds(readFileSync2(needsPath, "utf8")) < 3)
|
|
32838
|
+
missing.push(needsRel);
|
|
32839
|
+
}
|
|
32840
|
+
return { valid: missing.length === 0, missing };
|
|
32841
|
+
}
|
|
32842
|
+
function validateEngine(rootOrEngine, moduleUrl, { strict = false, requireKnowledge = false } = {}) {
|
|
32733
32843
|
const engine = resolveEngine(rootOrEngine);
|
|
32734
32844
|
const parent = resolve(engine, "..");
|
|
32735
32845
|
const errors = [];
|
|
@@ -32746,28 +32856,37 @@ function validateEngine(rootOrEngine, moduleUrl, { strict = false } = {}) {
|
|
|
32746
32856
|
else if (result.missing.length > 0)
|
|
32747
32857
|
errors.push(`Starter incomplete: ${result.missing.length} file(s) missing (use engine init --yes to add only missing files)`);
|
|
32748
32858
|
}
|
|
32749
|
-
|
|
32859
|
+
const knowledge = requireKnowledge ? checkKnowledge(engine) : void 0;
|
|
32860
|
+
if (knowledge && !knowledge.valid)
|
|
32861
|
+
errors.push(`Knowledge gate failed: ${knowledge.missing.join(", ")}`);
|
|
32862
|
+
return { ...result, valid: errors.length === 0, errors, created: [], ...knowledge ? { knowledge } : {} };
|
|
32750
32863
|
}
|
|
32751
32864
|
function python3Bin() {
|
|
32752
32865
|
const result = spawnSync("python3", ["--version"], { encoding: "utf8" });
|
|
32753
32866
|
return result.status === 0 ? "python3" : "";
|
|
32754
32867
|
}
|
|
32755
|
-
function ensureWorkbench(engine, moduleUrl) {
|
|
32868
|
+
function ensureWorkbench(engine, moduleUrl, { update = false } = {}) {
|
|
32756
32869
|
const destDir = join3(engine, "workbench");
|
|
32757
32870
|
mkdirSync2(destDir, { recursive: true });
|
|
32758
32871
|
const copied = [];
|
|
32872
|
+
const updated = [];
|
|
32759
32873
|
const skipped = [];
|
|
32760
32874
|
const src = workbenchSrc(moduleUrl);
|
|
32761
32875
|
for (const name of WORKBENCH_FILES) {
|
|
32762
32876
|
const dest = join3(destDir, name);
|
|
32763
|
-
|
|
32877
|
+
const from = join3(src, name);
|
|
32878
|
+
if (existsSync3(dest) && !update) {
|
|
32764
32879
|
skipped.push(name);
|
|
32765
32880
|
continue;
|
|
32766
32881
|
}
|
|
32767
|
-
|
|
32768
|
-
|
|
32882
|
+
const existed = existsSync3(dest);
|
|
32883
|
+
copyFileSync(from, dest);
|
|
32884
|
+
if (existed)
|
|
32885
|
+
updated.push(name);
|
|
32886
|
+
else
|
|
32887
|
+
copied.push(name);
|
|
32769
32888
|
}
|
|
32770
|
-
return { destDir, copied, skipped };
|
|
32889
|
+
return { destDir, copied, updated, skipped };
|
|
32771
32890
|
}
|
|
32772
32891
|
function buildWorkbench(engine) {
|
|
32773
32892
|
const python = python3Bin();
|
|
@@ -32799,7 +32918,7 @@ async function startWorkbench(engine, moduleUrl, { noOpen = false } = {}) {
|
|
|
32799
32918
|
const python = python3Bin();
|
|
32800
32919
|
if (!python)
|
|
32801
32920
|
return { ok: false, code: "PYTHON3_REQUIRED", message: "python3 is required for the workbench. Install Python 3 and retry." };
|
|
32802
|
-
ensureWorkbench(engine, moduleUrl);
|
|
32921
|
+
ensureWorkbench(engine, moduleUrl, { update: true });
|
|
32803
32922
|
const built = buildWorkbench(engine);
|
|
32804
32923
|
if (!built.ok)
|
|
32805
32924
|
return built;
|
|
@@ -32931,6 +33050,7 @@ function readCliVersion() {
|
|
|
32931
33050
|
return "0.0.0";
|
|
32932
33051
|
}
|
|
32933
33052
|
}
|
|
33053
|
+
var HEADLESS_RENDER_DISABLED = "PNG delivery is Studio Download (browser ZIP). CLI/MCP hosted PNG jobs are retired. Open the Run in Studio and use Download.";
|
|
32934
33054
|
var credentialPath = join4(homedir3(), ".config", "easysociable", "credentials.json");
|
|
32935
33055
|
function resolveInstallSkillIds(options) {
|
|
32936
33056
|
return parseInstallSkills(typeof options.skills === "string" ? options.skills : void 0);
|
|
@@ -33050,29 +33170,20 @@ async function applyInstallation(options) {
|
|
|
33050
33170
|
for (const skill of resolveInstallSkillIds(options))
|
|
33051
33171
|
await cp(join4(String(plan.source), skill), join4(host.skillsPath, skill), { recursive: true, force: false, errorOnExist: false });
|
|
33052
33172
|
}
|
|
33173
|
+
if (options.json !== true) {
|
|
33174
|
+
process.stdout.write(`Installed skills your Agent will use:
|
|
33175
|
+
easysociable-slideshow \u2014 turns a draft into slideshow pages you preview and download here
|
|
33176
|
+
easysociable-template \u2014 creates page templates
|
|
33177
|
+
`);
|
|
33178
|
+
}
|
|
33053
33179
|
return { ...plan, applied: true, backups };
|
|
33054
33180
|
}
|
|
33055
|
-
async function readJsonArgument(value) {
|
|
33056
|
-
if (existsSync4(value))
|
|
33057
|
-
return JSON.parse(await readFile(value, "utf8"));
|
|
33058
|
-
return JSON.parse(value);
|
|
33059
|
-
}
|
|
33060
33181
|
function mimeTypeFor(fileName) {
|
|
33061
33182
|
const extension = fileName.toLowerCase().split(".").pop();
|
|
33062
33183
|
if (extension === "jpg" || extension === "jpeg") return "image/jpeg";
|
|
33063
33184
|
if (extension === "webp") return "image/webp";
|
|
33064
33185
|
return "image/png";
|
|
33065
33186
|
}
|
|
33066
|
-
function renderSlots(value) {
|
|
33067
|
-
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
33068
|
-
throw new Error("Render slots must be a JSON object");
|
|
33069
|
-
const entries = Object.entries(value);
|
|
33070
|
-
for (const [key, item] of entries) {
|
|
33071
|
-
if (!(typeof item === "string" || typeof item === "number" || item === null))
|
|
33072
|
-
throw new Error(`Render slot ${key} must be a string, number or null`);
|
|
33073
|
-
}
|
|
33074
|
-
return Object.fromEntries(entries);
|
|
33075
|
-
}
|
|
33076
33187
|
function withClient(action) {
|
|
33077
33188
|
return async (...args) => {
|
|
33078
33189
|
const command = args.at(-1);
|
|
@@ -33087,69 +33198,6 @@ function withClient(action) {
|
|
|
33087
33198
|
}
|
|
33088
33199
|
};
|
|
33089
33200
|
}
|
|
33090
|
-
async function exportManifest(client, jobId, output) {
|
|
33091
|
-
const job = await client.getRenderJob(jobId);
|
|
33092
|
-
if (job.status !== "completed" || !job.manifest)
|
|
33093
|
-
throw new Error(`Render job ${jobId} is not completed or has no manifest`);
|
|
33094
|
-
const staging = await mkdtemp(join4(tmpdir(), "easysociable-export-"));
|
|
33095
|
-
try {
|
|
33096
|
-
for (const [index, artifact] of job.manifest.artifacts.entries()) {
|
|
33097
|
-
const response = await fetch(artifact.url);
|
|
33098
|
-
if (!response.ok) throw new Error(`Artifact download failed (${response.status})`);
|
|
33099
|
-
const bytes = Buffer.from(await response.arrayBuffer());
|
|
33100
|
-
const checksum = createHash("sha256").update(bytes).digest("hex");
|
|
33101
|
-
if (checksum !== artifact.sha256) throw new Error(`Artifact checksum mismatch for page ${index + 1}`);
|
|
33102
|
-
await writeFile(join4(staging, `${String(index + 1).padStart(2, "0")}.png`), bytes);
|
|
33103
|
-
}
|
|
33104
|
-
await writeFile(join4(staging, "manifest.json"), `${JSON.stringify(job.manifest, null, 2)}
|
|
33105
|
-
`);
|
|
33106
|
-
await rm(output, { recursive: true, force: true });
|
|
33107
|
-
await rename2(staging, output);
|
|
33108
|
-
return { jobId, output, pages: job.manifest.artifacts.length, manifest: job.manifest };
|
|
33109
|
-
} catch (error52) {
|
|
33110
|
-
await rm(staging, { recursive: true, force: true });
|
|
33111
|
-
throw error52;
|
|
33112
|
-
}
|
|
33113
|
-
}
|
|
33114
|
-
async function exportSlideshowRun(client, runId, output) {
|
|
33115
|
-
const manifest = await client.getSlideshowRunManifest(runId);
|
|
33116
|
-
const staging = await mkdtemp(join4(tmpdir(), "easysociable-slideshow-export-"));
|
|
33117
|
-
try {
|
|
33118
|
-
const pages = [];
|
|
33119
|
-
for (const artifact of manifest.artifacts) {
|
|
33120
|
-
const bytes = Buffer.from(await client.downloadSlideshowArtifact(runId, artifact.pageIndex));
|
|
33121
|
-
const checksum = createHash("sha256").update(bytes).digest("hex");
|
|
33122
|
-
if (checksum !== artifact.sha256)
|
|
33123
|
-
throw new Error(`Artifact checksum mismatch for page ${artifact.pageIndex + 1}`);
|
|
33124
|
-
const role = artifact.role || `page${artifact.pageIndex}`;
|
|
33125
|
-
const fileName = `${String(artifact.pageIndex + 1).padStart(2, "0")}-${role}.png`;
|
|
33126
|
-
await writeFile(join4(staging, fileName), bytes);
|
|
33127
|
-
pages.push({
|
|
33128
|
-
pageIndex: artifact.pageIndex,
|
|
33129
|
-
role,
|
|
33130
|
-
file: fileName,
|
|
33131
|
-
bytes: bytes.length,
|
|
33132
|
-
sha256: checksum,
|
|
33133
|
-
width: artifact.width,
|
|
33134
|
-
height: artifact.height
|
|
33135
|
-
});
|
|
33136
|
-
}
|
|
33137
|
-
const localManifest = {
|
|
33138
|
-
schema: "slideshow-hosted-export.v1",
|
|
33139
|
-
runId: manifest.runId,
|
|
33140
|
-
deckJobId: manifest.deckJobId,
|
|
33141
|
-
pages
|
|
33142
|
-
};
|
|
33143
|
-
await writeFile(join4(staging, "manifest.json"), `${JSON.stringify(localManifest, null, 2)}
|
|
33144
|
-
`);
|
|
33145
|
-
await rm(output, { recursive: true, force: true });
|
|
33146
|
-
await rename2(staging, output);
|
|
33147
|
-
return { runId, output, pages: pages.length, manifest: localManifest };
|
|
33148
|
-
} catch (error52) {
|
|
33149
|
-
await rm(staging, { recursive: true, force: true });
|
|
33150
|
-
throw error52;
|
|
33151
|
-
}
|
|
33152
|
-
}
|
|
33153
33201
|
function addCrudCommands(parent, resource, routes) {
|
|
33154
33202
|
jsonOption(parent.command("list").description(`List ${resource}`)).action(withClient(async (client) => client.requestJson("GET", routes.list)));
|
|
33155
33203
|
jsonOption(parent.command("get").requiredOption("--id <id>").description(`Get ${resource}`)).action(withClient(async (client, opts) => client.requestJson("GET", routes.get.replace(":id", String(opts.id)))));
|
|
@@ -33195,10 +33243,18 @@ function buildV1Cli() {
|
|
|
33195
33243
|
throw new Error(errors?.[0] ?? result.code ?? "engine init failed");
|
|
33196
33244
|
}
|
|
33197
33245
|
});
|
|
33198
|
-
jsonOption(engine.command("validate").description("Validate engine starter completeness or a run folder").option("--root <path>", "Parent directory or Content Engine path").option("--run <path>", "Run directory to validate").option("--require-pack", "Require pack-*.json on the run").option("--require-export", "Require export directory").option("--export <path>", "Export directory for --require-export")).action((...args) => {
|
|
33246
|
+
jsonOption(engine.command("validate").description("Validate engine starter completeness or a run folder").option("--root <path>", "Parent directory or Content Engine path").option("--run <path>", "Run directory to validate").option("--require-pack", "Require pack-*.json on the run").option("--require-export", "Require export directory").option("--export <path>", "Export directory for --require-export").option("--require-knowledge", "Require Identity (Role / What I build / POV) + boundaries; needs count only if needs/ exists")).action((...args) => {
|
|
33199
33247
|
const command = args.at(-1);
|
|
33200
33248
|
const opts = command.opts();
|
|
33201
33249
|
if (opts.run) {
|
|
33250
|
+
if (opts.requireKnowledge === true) {
|
|
33251
|
+
const engineRoot = resolve2(String(opts.run), "..", "..");
|
|
33252
|
+
const knowledge = checkKnowledge(engineRoot);
|
|
33253
|
+
if (!knowledge.valid) {
|
|
33254
|
+
print({ valid: false, missing: knowledge.missing, knowledge, action: "validated" }, commandWantsJson(command));
|
|
33255
|
+
throw new Error(`Knowledge gate failed: ${knowledge.missing.join(", ")}`);
|
|
33256
|
+
}
|
|
33257
|
+
}
|
|
33202
33258
|
const result = validateRun(CLI_MODULE_URL, {
|
|
33203
33259
|
run: String(opts.run),
|
|
33204
33260
|
requirePack: opts.requirePack === true,
|
|
@@ -33215,31 +33271,30 @@ function buildV1Cli() {
|
|
|
33215
33271
|
}
|
|
33216
33272
|
if (!opts.root)
|
|
33217
33273
|
throw new Error("Pass --root <path> or --run <path>.");
|
|
33218
|
-
const report = validateEngine(String(opts.root), CLI_MODULE_URL, {
|
|
33274
|
+
const report = validateEngine(String(opts.root), CLI_MODULE_URL, {
|
|
33275
|
+
strict: true,
|
|
33276
|
+
requireKnowledge: opts.requireKnowledge === true
|
|
33277
|
+
});
|
|
33219
33278
|
print({ ...report, action: "validated" }, commandWantsJson(command));
|
|
33220
33279
|
if (!report.valid)
|
|
33221
33280
|
throw new Error(report.errors[0] ?? "engine validate failed");
|
|
33222
33281
|
});
|
|
33223
|
-
jsonOption(engine.command("serve").description("
|
|
33282
|
+
jsonOption(engine.command("serve").description("Sync workbench runtime from CLI, rebuild, start on :8765").option("--engine <path>", "Content Engine path or parent", defaultEngineRoot()).option("--no-open", "Do not open a browser")).action(async (...args) => {
|
|
33224
33283
|
const command = args.at(-1);
|
|
33225
33284
|
const opts = command.opts();
|
|
33226
33285
|
const enginePath = resolveEngine(String(opts.engine));
|
|
33227
|
-
ensureWorkbench(enginePath, CLI_MODULE_URL);
|
|
33228
|
-
const built = buildWorkbench(enginePath);
|
|
33229
|
-
if (!built.ok)
|
|
33230
|
-
throw new Error(built.message);
|
|
33231
33286
|
const started = await startWorkbench(enginePath, CLI_MODULE_URL, { noOpen: opts.noOpen === true });
|
|
33232
33287
|
print({ action: "serve", engine: enginePath, ...started }, commandWantsJson(command));
|
|
33233
33288
|
if (!started.ok)
|
|
33234
33289
|
throw new Error("message" in started ? String(started.message) : "engine serve failed");
|
|
33235
33290
|
});
|
|
33236
|
-
jsonOption(engine.command("build").description("
|
|
33291
|
+
jsonOption(engine.command("build").description("Sync workbench runtime from CLI, then rebuild workbench/index.html").option("--engine <path>", "Content Engine path or parent", defaultEngineRoot())).action((...args) => {
|
|
33237
33292
|
const command = args.at(-1);
|
|
33238
33293
|
const opts = command.opts();
|
|
33239
33294
|
const enginePath = resolveEngine(String(opts.engine));
|
|
33240
|
-
ensureWorkbench(enginePath, CLI_MODULE_URL);
|
|
33295
|
+
const workbench = ensureWorkbench(enginePath, CLI_MODULE_URL, { update: true });
|
|
33241
33296
|
const built = buildWorkbench(enginePath);
|
|
33242
|
-
print({ action: "build", engine: enginePath, ...built }, commandWantsJson(command));
|
|
33297
|
+
print({ action: "build", engine: enginePath, workbench, ...built }, commandWantsJson(command));
|
|
33243
33298
|
if (!built.ok)
|
|
33244
33299
|
throw new Error(built.message);
|
|
33245
33300
|
});
|
|
@@ -33306,8 +33361,12 @@ function buildV1Cli() {
|
|
|
33306
33361
|
jsonOption(slideshows.command("archive").requiredOption("--id <id>")).action(withClient(async (client, opts) => client.archiveSlideshowRun(String(opts.id))));
|
|
33307
33362
|
jsonOption(slideshows.command("restore").requiredOption("--id <id>")).action(withClient(async (client, opts) => client.restoreSlideshowRun(String(opts.id))));
|
|
33308
33363
|
jsonOption(slideshows.command("delete").requiredOption("--id <id>")).action(withClient(async (client, opts) => client.trashSlideshowRun(String(opts.id))));
|
|
33309
|
-
jsonOption(slideshows.command("render").requiredOption("--id <id>").requiredOption("--idempotency-key <key>")).action(withClient(async (
|
|
33310
|
-
|
|
33364
|
+
jsonOption(slideshows.command("render").description("Retired: PNG packs come from Studio Download").requiredOption("--id <id>").requiredOption("--idempotency-key <key>")).action(withClient(async () => {
|
|
33365
|
+
throw new Error(HEADLESS_RENDER_DISABLED);
|
|
33366
|
+
}));
|
|
33367
|
+
jsonOption(slideshows.command("export").description("Retired: PNG packs come from Studio Download").requiredOption("--id <id>").requiredOption("--output <path>")).action(withClient(async () => {
|
|
33368
|
+
throw new Error(HEADLESS_RENDER_DISABLED);
|
|
33369
|
+
}));
|
|
33311
33370
|
const renders = program.command("renders").description("Inspect final render jobs");
|
|
33312
33371
|
jsonOption(renders.command("create-asset").requiredOption("--file <path>").requiredOption("--idempotency-key <key>")).action(withClient(async (client, opts) => {
|
|
33313
33372
|
const fileName = String(opts.file);
|
|
@@ -33322,16 +33381,15 @@ function buildV1Cli() {
|
|
|
33322
33381
|
idempotencyKey: String(opts.idempotencyKey)
|
|
33323
33382
|
});
|
|
33324
33383
|
}));
|
|
33325
|
-
jsonOption(renders.command("create").requiredOption("--template-id <id>").requiredOption("--slots <json-or-file>").option("--format <format>", "Final output format", "png").requiredOption("--idempotency-key <key>")).action(withClient(async (
|
|
33326
|
-
|
|
33327
|
-
|
|
33328
|
-
outputFormats: [String(opts.format)],
|
|
33329
|
-
idempotencyKey: String(opts.idempotencyKey)
|
|
33330
|
-
})));
|
|
33384
|
+
jsonOption(renders.command("create").description("Retired: PNG packs come from Studio Download").requiredOption("--template-id <id>").requiredOption("--slots <json-or-file>").option("--format <format>", "Final output format", "png").requiredOption("--idempotency-key <key>")).action(withClient(async () => {
|
|
33385
|
+
throw new Error(HEADLESS_RENDER_DISABLED);
|
|
33386
|
+
}));
|
|
33331
33387
|
jsonOption(renders.command("get").requiredOption("--id <id>")).action(withClient(async (client, opts) => client.getRenderJob(String(opts.id))));
|
|
33332
33388
|
jsonOption(renders.command("manifest").requiredOption("--id <id>")).action(withClient(async (client, opts) => client.getRenderManifest(String(opts.id))));
|
|
33333
33389
|
jsonOption(renders.command("wait").requiredOption("--id <id>")).action(withClient(async (client, opts) => client.pollRenderJob(String(opts.id))));
|
|
33334
|
-
jsonOption(renders.command("export").requiredOption("--id <id>").requiredOption("--output <path>")).action(withClient(async (
|
|
33390
|
+
jsonOption(renders.command("export").description("Retired: PNG packs come from Studio Download").requiredOption("--id <id>").requiredOption("--output <path>")).action(withClient(async () => {
|
|
33391
|
+
throw new Error(HEADLESS_RENDER_DISABLED);
|
|
33392
|
+
}));
|
|
33335
33393
|
const mcp = program.command("mcp").description("Install and run the unified EasySociable MCP server");
|
|
33336
33394
|
jsonOption(mcp.command("install").requiredOption("--host <host>", "codex, claude, hermes, or openclaw").option("--config-path <path>")).action((...args) => {
|
|
33337
33395
|
const command = args.at(-1);
|