@easysociable/cli 0.1.11 → 0.1.13

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@easysociable/cli",
3
- "version": "0.1.11",
3
+ "version": "0.1.13",
4
4
  "description": "Agent-first CLI for EasySociable: Content Engine, Template, Slideshow, and MCP",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -37,13 +37,6 @@
37
37
  "LICENSE",
38
38
  "README.md"
39
39
  ],
40
- "scripts": {
41
- "typecheck": "tsc --noEmit",
42
- "test": "vitest run",
43
- "build": "tsup",
44
- "prepack": "node scripts/prepack.mjs && pnpm build",
45
- "pack:check": "npm pack --dry-run"
46
- },
47
40
  "publishConfig": {
48
41
  "access": "public",
49
42
  "registry": "https://registry.npmjs.org/"
@@ -52,13 +45,19 @@
52
45
  "commander": "^11.1.0"
53
46
  },
54
47
  "devDependencies": {
55
- "@easysociable/mcp-server": "workspace:*",
56
- "@easysociable/template-gateway-client": "workspace:*",
57
- "@easysociable/tsconfig": "workspace:*",
58
- "@easysociable/vitest-config": "workspace:*",
59
48
  "@types/node": "^22.14.0",
60
49
  "tsup": "^8.0.2",
61
50
  "typescript": "^5.8.3",
62
- "vitest": "^1.3.1"
51
+ "vitest": "^1.3.1",
52
+ "@easysociable/mcp-server": "0.0.0",
53
+ "@easysociable/tsconfig": "0.0.0",
54
+ "@easysociable/template-gateway-client": "0.0.0",
55
+ "@easysociable/vitest-config": "0.0.0"
56
+ },
57
+ "scripts": {
58
+ "typecheck": "tsc --noEmit",
59
+ "test": "vitest run",
60
+ "build": "tsup",
61
+ "pack:check": "npm pack --dry-run"
63
62
  }
64
- }
63
+ }
@@ -23,7 +23,7 @@ export const PLATFORM_CAPS = {
23
23
  const FORBIDDEN_PACK_KEYS = ['deck_template_id', 'deckTemplateId']
24
24
 
25
25
  const PACK_KEYS = new Set(['schemaVersion', 'platform', 'title', 'pages'])
26
- const PAGE_KEYS = new Set(['pageTemplateId', 'role', 'slots'])
26
+ const PAGE_KEYS = new Set(['layoutFamilyId', 'pageTemplateId', 'role', 'slots'])
27
27
  export const RUN_FILE_STATUSES = [
28
28
  'RUN_OPEN', 'BRIEF_WAIT', 'DRAFTED', 'EDIT_WAIT', 'SCORED',
29
29
  'READY_TO_POST', 'PUBLISHED', 'HOLD', 'KILLED', 'SUPERSEDED',
@@ -97,8 +97,9 @@ export function validateContentPack(pack, options = {}) {
97
97
  }
98
98
  pushUnknownKeys(errors, page, PAGE_KEYS, label)
99
99
  if (!PAGE_ROLES.includes(page.role)) errors.push(`${label}.role: invalid page role`)
100
- if (typeof page.pageTemplateId !== 'string' || page.pageTemplateId.length === 0) {
101
- errors.push(`${label}.pageTemplateId: required and must be a non-empty string`)
100
+ const layoutRef = page.layoutFamilyId ?? page.pageTemplateId
101
+ if (typeof layoutRef !== 'string' || layoutRef.length === 0) {
102
+ errors.push(`${label}.layoutFamilyId: required (or pageTemplateId) and must be a non-empty string`)
102
103
  }
103
104
  if (!isRecord(page.slots)) {
104
105
  errors.push(`${label}.slots: must be an object`)
@@ -51,17 +51,13 @@ V1 expects an Agent (Grok Bot, Codex, Claude Code, …) to drive setup. The webs
51
51
  ## Lazy auth (Agent script)
52
52
 
53
53
  When a Gateway call returns `AUTH_REQUIRED`, `API_KEY_INVALID`, or the CLI says
54
- `Run easysociable auth login`, respond with:
54
+ `Run easysociable auth login`, run `easysociable auth login` yourself (it waits
55
+ up to 5 minutes for the browser approval) and tell the user:
55
56
 
56
57
  ```text
57
- EasySociable needs a workspace API key before it can create Brands, images, drafts or Slideshow Runs on the Gateway.
58
-
59
- 1. Open https://my.easysociable.com/auth/signup (or sign in with Google).
60
- 2. Verify your email if you used password signup (required before API keys).
61
- 3. Dashboard → API Keys → Create API key → copy the secret once.
62
- 4. Run: easysociable auth login --api-key <paste-key> --gateway-url https://gateway.easysociable.com
63
-
64
- Tell me when that is done and I will continue.
58
+ EasySociable needs to connect to your account. I'm running `easysociable auth login` —
59
+ a browser tab will open: sign in (Google works, free) and click "Authorize Agent".
60
+ I'll continue as soon as you approve.
65
61
  ```
66
62
 
67
63
  After `auth login` succeeds, retry the failed operation with the same
@@ -3,9 +3,10 @@ name: easysociable-slideshow
3
3
  description: >
4
4
  Create, list, update and review durable multi-page Slideshow Runs for
5
5
  EasySociable from a local Content Pack. Name the argument (arc) first, then
6
- pick a Page Template per page by platform, canvas, slotSummary and density —
7
- never default Cover→Point→Steps→Recap→CTA. Page 1 must be a cover or hook
8
- class template; those templates must not appear on later pages. Use the
6
+ pick a Layout Family per page (one layout, adapted to every platform) by
7
+ role, slotSummary and density — never default Cover→Point→Steps→Recap→CTA.
8
+ A Formula with a Look already fixes each page's Layout Family. Page 1 must
9
+ be a cover or hook class family; those must not appear on later pages. Use the
9
10
  unified `easysociable` CLI or MCP, open Studio to preview and edit, then
10
11
  ask the user to click Download for a PNG ZIP. CLI/MCP must not call
11
12
  render/export or create_render_job for final pixels. Runs remain in the
@@ -14,7 +15,9 @@ description: >
14
15
 
15
16
  # EasySociable Slideshow Skill
16
17
 
17
- A Slideshow Run is a composition of explicit single-page Templates.
18
+ A Slideshow Run is a composition of explicit Layout Families, one per page.
19
+ A Layout Family is one layout whose templates differ only by platform canvas,
20
+ so one Run yields the carousel for every platform (Studio switches variants).
18
21
  It is not a reusable Carousel/Deck Template and it is not a public post.
19
22
  Page order is the argument of **this pack**, not a catalog recipe.
20
23
 
@@ -23,20 +26,31 @@ Page order is the argument of **this pack**, not a catalog recipe.
23
26
  1. Read a local `content-pack.v1` from the Content Engine.
24
27
  2. Use the unified `easysociable` CLI or the unified MCP server. All hosted
25
28
  calls go through Gateway; never call Directus, R2, Stripe or private services.
26
- 3. Choose a Brand (or Profile/Theme) and an explicit Page Template for every
27
- page. The server never silently chooses or replaces a Page Template.
28
- Prefer templates already chosen on the Content Engine pack (**Template
29
- Selection** after **Page Contracts**). Otherwise select by **platform +
30
- canvas + slotSummary + density + layoutFamily**. `role` / `supportedRoles`
31
- are weak retrieval tags, not sequence position.
29
+ 3. Choose a Brand (or Profile/Theme) and an explicit Layout Family for every
30
+ page, sent as `layoutFamilyId` in the pack (Gateway resolves it to the
31
+ family's template on the Run's native canvas; `pageTemplateId` is still
32
+ accepted). The server never silently chooses or replaces a layout.
33
+ Order of precedence: (a) a Formula **Look** (see Formula handoff),
34
+ (b) families already chosen on the Content Engine pack (**Template
35
+ Selection** after **Page Contracts**), (c) a shortlist from
36
+ `easysociable slideshows recommend --file contracts.json --seed <slug>`
37
+ (MCP `recommend_slideshow_templates`) — pick one `familyId` per page with a reason.
38
+ The recommender filters platform + native canvas + slotSummary + cover rule,
39
+ demotes Layout Families used in the owner's recent Runs, and keeps one
40
+ unused family per page. `role` / `supportedRoles` are weak retrieval tags,
41
+ not sequence position. Never browse with bare `templates list` (first 20
42
+ ids only); use `--platform <p> --all` if you must see the full catalog.
43
+ Do not copy a previous pack's Template Selection as the default.
32
44
  4. **Cover / hook placement (hard):** a template is cover/hook class when
33
45
  `supportedRoles` includes `cover` or `hook`. `pages[0]` must use one.
34
46
  Cover/hook class templates must not appear on any later page. Later pages
35
47
  use metric / quote / compare / value / steps / cta / etc. Do not put a
36
48
  Point or metric-only template on page 1 to “open with a number” — pick a
37
49
  cover or hook template whose slots fit the opening copy.
38
- 5. A Run has up to 8 pages on Free and 20 on paid, one supported platform
39
- (`tiktok`, `instagram`, `linkedin` or `threads`) and one Brand across pages.
50
+ 5. A Run has up to 8 pages on Free and 20 on paid, one native platform
51
+ (`tiktok`, `instagram`, `linkedin` or `threads`; it sets the page cap and
52
+ the canvas edited first) and one Brand across pages. Studio renders the
53
+ same Run for every platform its Layout Families support.
40
54
  6. Topology is fixed after creation: no add, copy, delete, reorder or template
41
55
  switch. Page-instance slot/layout/type/style/decoration edits remain allowed
42
56
  in Studio.
@@ -45,8 +59,8 @@ Page order is the argument of **this pack**, not a catalog recipe.
45
59
  or MCP `render_slideshow_run` / `create_render_job`. Those return
46
60
  `HEADLESS_RENDER_DISABLED`.
47
61
  8. Before creating a new Run, list/find prior Runs by `contentSlug`. **Update**
48
- the same Run only when page count, pageTemplateIds, and intended sequence
49
- still match. A different arc or template set is a **new Run** — never PATCH
62
+ the same Run only when page count, Layout Families, and intended sequence
63
+ still match. A different arc or family set is a **new Run** — never PATCH
50
64
  new copy into a locked Cover-Point-Steps-Recap-CTA skeleton.
51
65
  8b. **Knowledge hard gate (every create, not only the first Run):** before
52
66
  `create_run` / `slideshows create`, read Identity (Role / What I build /
@@ -56,13 +70,16 @@ Page order is the argument of **this pack**, not a catalog recipe.
56
70
  If `needs/` exists, `needs/_index.md` ≥ 3 `N-` rows; if `needs/` is absent, skip that count. Fail → hand back to
57
71
  **easysociable-content** / refuse create; list missing files. Do not add
58
72
  Gateway or MCP params. User must say **强制继续** / **force continue**
59
- to call Gateway.
73
+ to call Gateway. **Exempt:** Formula handoff Runs (prompt names
74
+ `Formula: F-…`) — the Formula supplies the arc and the user supplies the
75
+ topic, so a first-time user with no Content Engine is not blocked.
60
76
  8c. **Identity chain (ADR-0036, hard):** before create, the CLI must be
61
77
  logged in with the **user's Dashboard Workspace API key** (same account
62
78
  that will open Studio). Refuse fixture `workspace_local` / local
63
79
  `test-key` unless the user explicitly asked for a local fixture
64
- (`--allow-local-fixture`). Order: Studio login → create API key →
65
- `easysociable auth login --api-key <key>` → create Run → open
80
+ (`--allow-local-fixture`). Order: `easysociable auth login` (opens the
81
+ browser; the user approves once and the key is stored — use
82
+ `--api-key <key>` only when headless) → create Run → open
66
83
  `studioUrl` while logged in as that user. If Studio shows “belongs to
67
84
  another account”, recreate with the current key — do not invent
68
85
  cross-workspace access.
@@ -81,10 +98,13 @@ Page order is the argument of **this pack**, not a catalog recipe.
81
98
  `python3 scripts/validate-pack.py runs/<slug>/pack.md` (in the Content Engine).
82
99
  Refuse create if contracts are empty or contain `templateId`.
83
100
  3. Resolve or create the user's Brand through the unified CLI/MCP.
84
- 4. Prefer pack **Template Selection** ids. If re-listing the catalog, verify
85
- hard filters and cover/hook placement; never place a cover/hook class
86
- template after page 1. Record Layout Family evidence as `hypothesis` unless
87
- comparable history supports `tested` / `supported`.
101
+ 4. Use the Formula Look's families, else pack **Template Selection**. Otherwise run
102
+ `easysociable slideshows recommend --file contracts.json --seed <slug> --json`
103
+ and choose a `familyId` from each page's `candidates`; never place a cover/hook class
104
+ family after page 1. Report `gaps` (pages with < 2 role-matching
105
+ templates) to the user as authoring backlog. Record Layout Family evidence
106
+ as `hypothesis` unless published comparable results support `tested` /
107
+ `supported` — a template having been used before is not evidence.
88
108
  5. List existing Runs when the Pack has a stable content slug:
89
109
 
90
110
  ```bash
@@ -99,7 +119,8 @@ Page order is the argument of **this pack**, not a catalog recipe.
99
119
  ```
100
120
 
101
121
  Fail → refuse; return to **easysociable-content**. **强制继续** / **force continue**
102
- is the only override (conversational — not a CLI flag). Then:
122
+ is the only override (conversational — not a CLI flag). Formula handoff
123
+ Runs skip this knowledge check (rule 8b) but not the identity gate. Then:
103
124
 
104
125
  ```bash
105
126
  easysociable slideshows create --file ./pack.json --json
@@ -110,6 +131,29 @@ Page order is the argument of **this pack**, not a catalog recipe.
110
131
  9. After explicit user confirmation, tell them to click **Download** in Studio.
111
132
  Do not render or export from CLI/MCP.
112
133
 
134
+ ## Formula handoff (prompt names a `Formula: F-…` id)
135
+
136
+ 1. `easysociable formulas get --id <id> --json` (falls back to the hosted
137
+ catalog). Not found → tell the user; do not guess a structure.
138
+ 2. The formula's `beats` are the page order: one page per beat, same roles,
139
+ same count. Its `title_template` with `{X}` = the user's topic is the arc
140
+ line, so rule 10 is satisfied by the formula, not by P0 family names.
141
+ 3. Write each page's copy from `beat.fill` and the user's topic. Ask at most
142
+ one question when tip/point pages need facts the topic doesn't supply.
143
+ Never copy sentences from the formula's viral example posts.
144
+ 4. **Look = copy the layout.** If the prompt names `Look: L-…` (else use the
145
+ formula's first entry in `looks`), set each page's `layoutFamilyId` to
146
+ `look.slides["<1-based slide number>"]` if present, else
147
+ `look.layouts[beat.role]`. Do not run `slideshows recommend` for those
148
+ pages and ignore the "demote recently used families" preference — the
149
+ user asked for this layout. Only roles missing from the Look fall back to
150
+ the recommender. Copy layout only: colours and fonts come from the user's
151
+ Brand. If a Look family has image slots, ask the user for images (or say
152
+ which slots are empty) instead of delivering blank image slots.
153
+ 5. Turn beats into Page Contracts, then continue at Workflow step 3
154
+ (Brand → families → identity gate → create → Studio). The knowledge gate
155
+ (rule 8b) does not apply to Formula handoff Runs.
156
+
113
157
  ## Failure handling
114
158
 
115
159
  - If the knowledge hard gate fails, do not create the Run. Hand back to
@@ -119,6 +163,8 @@ Page order is the argument of **this pack**, not a catalog recipe.
119
163
  class template, stop and rebuild the Pack. Do not create the Run.
120
164
  - If a page template, slot or image is invalid, return the structured Gateway
121
165
  error to the Agent; do not substitute another template.
166
+ - `LAYOUT_FAMILY_NOT_FOUND`: the family has no template for the Run's
167
+ platform. Tell the user and pick another platform or family; do not guess.
122
168
  - If Download is exhausted (`USAGE_LIMIT_REACHED`) or past due, tell the user
123
169
  to upgrade or update billing.
124
170
  - If a Run was deleted, or Gateway returns `RUN_TOPOLOGY_LOCKED` because the
@@ -1,8 +1,11 @@
1
1
  # ContentPack v1
2
2
 
3
3
  Page `role` is a **weak retrieval tag** (layout-ish), not sequence position.
4
- `pageTemplateId` is the explicit published single-page template chosen by the
5
- Agent. `slots` are public values only. Do not add a `deck_template_id`,
4
+ `layoutFamilyId` is the explicit Layout Family chosen by the Agent (from a
5
+ Formula Look or the recommender's `familyId`); Gateway resolves it to that
6
+ family's template on the pack platform's canvas, and Studio derives the other
7
+ platforms from the same family. `pageTemplateId` (one exact template) is still
8
+ accepted and wins when both are sent. `slots` are public values only. Do not add a `deck_template_id`,
6
9
  `bindingMap`, AST, ContentDocument, or product `arc` / `pageSequence`.
7
10
 
8
11
  The Gateway validates each `role` against the closed enum and that slots exist.
@@ -21,10 +24,10 @@ Opening beat is cost; page 1 is still a hook-class template.
21
24
  "platform": "tiktok",
22
25
  "title": "Stop briefing a blank canvas",
23
26
  "pages": [
24
- { "role": "hook", "pageTemplateId": "tpl_hook_001", "slots": { "text_0": "You finish the copy. Then you start over.", "text_1": "The design file kept none of the argument." } },
25
- { "role": "point", "pageTemplateId": "tpl_stack_001", "slots": { "text_0": "Roles, Brand, Layouts persist" } },
26
- { "role": "steps", "pageTemplateId": "tpl_stair_001", "slots": { "text_0": "Use them in that order" } },
27
- { "role": "cta", "pageTemplateId": "tpl_close_001", "slots": { "text_0": "Don't brief a blank canvas" } }
27
+ { "role": "hook", "layoutFamilyId": "fam_hook_001", "slots": { "text_0": "You finish the copy. Then you start over.", "text_1": "The design file kept none of the argument." } },
28
+ { "role": "point", "layoutFamilyId": "fam_stack_001", "slots": { "text_0": "Roles, Brand, Layouts persist" } },
29
+ { "role": "steps", "layoutFamilyId": "fam_stair_001", "slots": { "text_0": "Use them in that order" } },
30
+ { "role": "cta", "layoutFamilyId": "fam_close_001", "slots": { "text_0": "Don't brief a blank canvas" } }
28
31
  ]
29
32
  }
30
33
  ```
@@ -44,10 +47,10 @@ Opening beat is cost; page 1 is still a hook-class template.
44
47
  }
45
48
  ```
46
49
 
47
- Pick templates by **platform + canvas + slotSummary + density**, not by matching
48
- the beat name to a family named Cover / Point / Steps / Recap / CTA. Page 1
49
- must still be cover/hook class.
50
+ Pick families by **slotSummary + density** (or take them from a Formula Look),
51
+ not by matching the beat name to a family named Cover / Point / Steps / Recap /
52
+ CTA. Page 1 must still be cover/hook class.
50
53
 
51
54
  The renderer accepts any supported page count within the platform cap. A newly
52
- published Page Template can be selected in a new Run without creating a
55
+ published Layout Family can be selected in a new Run without creating a
53
56
  carousel asset.
@@ -7,20 +7,23 @@
7
7
  stop and hand back to **easysociable-content** — do not invent page
8
8
  purposes from catalog family names.
9
9
  3. Build `content-pack.v1` from that argument. Page count follows the beats
10
- (TikTok often 4–8), not the number of P0 families. Carry the chosen
11
- `pageTemplateId`s from Template Selection (explicit — server must not
12
- silent-replace).
10
+ (TikTok often 4–8), not the number of P0 families. Each page carries an
11
+ explicit `layoutFamilyId` (explicit — server must not silent-replace):
12
+ Formula handoff with a Look → `look.slides[slideNumber] ?? look.layouts[beat.role]`; else the pack's
13
+ Template Selection. One Run covers every platform the families support.
13
14
  4. Check platform hardMin/hardMax.
14
- 5. List published Page Templates only to **verify** hard filters still hold:
15
- platform → canvas → slotSummary → density → page-position cover/hook.
16
- Prefer ranking by Layout Family (`layoutFamily`) + history; `supportedRoles`
17
- is a weak tag. `pages[0]` must be cover/hook class. Do not use that class on
18
- later pages. Prefer families already recorded on linked W- judgments
19
- (`fits` / `avoid` / `trial`) when comparable evidence exists.
15
+ 5. No Look and no Template Selection → shortlist with
16
+ `easysociable slideshows recommend --file contracts.json --seed <slug> --json`
17
+ (MCP `recommend_slideshow_templates`). Input is the Page Contracts:
18
+ `{ platform, pages: [{ role, density?, slotSummary?: { text, number, image }, requiresImage? }] }`.
19
+ Pick one candidate `familyId` per page and record the reason; `supportedRoles` is a
20
+ weak tag. `pages[0]` must be cover/hook class. Do not use that class on
21
+ later pages. W- judgments (`fits` / `avoid`) with comparable evidence may
22
+ override the recommender's order. Surface `gaps` to the user.
20
23
  6. If `contentSlug` already has a Run: update only when topology matches
21
- (same page count and `pageTemplateId`s). Otherwise create a new Run.
22
- 7. **Before** `create_run` / `slideshows create` (every create, not only the
23
- first Run): check the knowledge hard gate — Identity Role / What I build /
24
+ (same page count and Layout Families). Otherwise create a new Run.
25
+ 7. **Before** `create_run` / `slideshows create` (every create except
26
+ Formula handoff Runs): check the knowledge hard gate — Identity Role / What I build /
24
27
  Point of view have no `(fill)` and are non-empty; `boundaries.md` exists
25
28
  with Not covering and Never claim non-empty; if `needs/` exists, ≥3 `N-`
26
29
  rows, else skip. Read the files or run
@@ -29,12 +32,13 @@
29
32
  files. User must say **强制继续** / **force continue** to call Gateway.
30
33
  No new Gateway or MCP params.
31
34
  7b. **Identity chain (ADR-0036):** confirm CLI auth is the user's Dashboard
32
- Workspace API key (not `workspace_local` / `test-key`). If needed:
33
- Studio login → Dashboard create key →
34
- `easysociable auth login --api-key <key>`. Refuse create on fixture
35
+ Workspace API key (not `workspace_local` / `test-key`). If needed run
36
+ `easysociable auth login` (browser approval; `--api-key <key>` only when
37
+ headless). Refuse create on fixture
35
38
  identity unless the user asked for `--allow-local-fixture`.
36
39
  8. Call `create_run` / `slideshows create` through Gateway with the explicit
37
- template ids from the pack.
40
+ `layoutFamilyId`s from the pack. `LAYOUT_FAMILY_NOT_FOUND` → the family has
41
+ no template for this platform; tell the user, do not guess.
38
42
  9. Save `runId`, `studioUrl`, and `status=draft`. Tell the user to open
39
43
  `studioUrl` **while logged into the same Studio account**.
40
44
  10. Do not call a Deck API, create a carousel template, or send a product