@easysociable/cli 0.1.2 → 0.1.3

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.
Files changed (120) hide show
  1. package/README.md +29 -21
  2. package/dist/easysociable.js +481 -52
  3. package/dist/easysociable.js.map +1 -1
  4. package/package.json +3 -2
  5. package/skills/ONBOARDING.md +20 -16
  6. package/skills/easysociable-content/SKILL.md +29 -104
  7. package/skills/easysociable-slideshow/SKILL.md +4 -3
  8. package/skills/easysociable-template/SKILL.md +26 -24
  9. package/skills/easysociable-template/references/CATALOG_METADATA.md +2 -2
  10. package/skills/easysociable-template/references/DESIGN_V2_1.md +53 -2
  11. package/skills/easysociable-template/references/GATEWAY.md +7 -2
  12. package/skills/easysociable-template/references/PLATFORM_SPECS.md +11 -3
  13. package/skills/easysociable-template/references/THEME_TOKENS.md +1 -1
  14. package/skills/easysociable-template/references/fixtures/image-reference.design-plan.json +74 -0
  15. package/skills/easysociable-template/references/fixtures/image-reference.visual-qa.json +28 -0
  16. package/skills/easysociable-template/scripts/validate-design-v2.mjs +97 -0
  17. package/skills/easysociable-template/workflows/ASSET_PLAN.md +2 -1
  18. package/skills/easysociable-template/workflows/AUTHORING_FROM_BRIEF.md +4 -4
  19. package/skills/easysociable-template/workflows/AUTHORING_FROM_IMAGE.md +66 -16
  20. package/skills/easysociable-template/workflows/AUTHORING_STUDIO.md +28 -15
  21. package/skills/easysociable-template/workflows/DESIGN_BRIEF.md +4 -3
  22. package/skills/easysociable-template/workflows/MULTI_PLATFORM_FAMILY.md +81 -0
  23. package/skills/easysociable-template/workflows/PUBLISH_FROM_DRAFT.md +1 -1
  24. package/skills/easysociable-template/workflows/VISUAL_QA.md +10 -0
  25. package/skills/easysociable-content/INSTALL.md +0 -60
  26. package/skills/easysociable-content/platforms/claude.md +0 -4
  27. package/skills/easysociable-content/platforms/codex.md +0 -4
  28. package/skills/easysociable-content/platforms/hermes.md +0 -4
  29. package/skills/easysociable-content/platforms/openclaw.md +0 -4
  30. package/skills/easysociable-content/references/CLI.md +0 -40
  31. package/skills/easysociable-content/references/CONTRACT_SYNC.md +0 -42
  32. package/skills/easysociable-content/references/MCP.md +0 -15
  33. package/skills/easysociable-content/references/PAGE_PACK.md +0 -129
  34. package/skills/easysociable-content/references/PLATFORM_GUIDE.md +0 -36
  35. package/skills/easysociable-content/references/RUN_LAYOUT.md +0 -73
  36. package/skills/easysociable-content/references/TROUBLESHOOTING.md +0 -13
  37. package/skills/easysociable-content/references/VAULT.md +0 -40
  38. package/skills/easysociable-content/references/VOICE.md +0 -16
  39. package/skills/easysociable-content/scripts/package-skill.mjs +0 -49
  40. package/skills/easysociable-content/scripts/setup.mjs +0 -200
  41. package/skills/easysociable-content/scripts/setup.test.mjs +0 -82
  42. package/skills/easysociable-content/workflows/ANALYSIS_AND_COVERAGE.md +0 -17
  43. package/skills/easysociable-content/workflows/CONTENT_EXPORT.md +0 -24
  44. package/skills/easysociable-content/workflows/GETTING_STARTED.md +0 -40
  45. package/skills/easysociable-content/workflows/MCP_FIRST.md +0 -5
  46. package/skills/easysociable-content/workflows/OUT_OF_SCOPE.md +0 -18
  47. package/skills/easysociable-content/workflows/PACK_AUTHORING.md +0 -42
  48. package/skills/easysociable-content/workflows/SWIPE_CAPTURE.md +0 -18
  49. package/skills/easysociable-content/workflows/TOPIC_DRAFT.md +0 -29
  50. package/skills/easysociable-content/workflows/WORKING_DRAFT.md +0 -19
  51. /package/{skills/easysociable-content → content-engine}/fixtures/golden-run-en/draft.md +0 -0
  52. /package/{skills/easysociable-content → content-engine}/fixtures/golden-run-en/idea.md +0 -0
  53. /package/{skills/easysociable-content → content-engine}/fixtures/golden-run-en/pack-tiktok.json +0 -0
  54. /package/{skills/easysociable-content → content-engine}/scripts/contracts.mjs +0 -0
  55. /package/{skills/easysociable-content → content-engine}/scripts/export-contracts.mjs +0 -0
  56. /package/{skills/easysociable-content → content-engine}/scripts/fixture.test.mjs +0 -0
  57. /package/{skills/easysociable-content → content-engine}/scripts/starter.mjs +0 -0
  58. /package/{skills/easysociable-content → content-engine}/scripts/validate-export.mjs +0 -0
  59. /package/{skills/easysociable-content → content-engine}/scripts/validate-pack.mjs +0 -0
  60. /package/{skills/easysociable-content → content-engine}/scripts/validate-run.mjs +0 -0
  61. /package/{skills/easysociable-content → content-engine}/scripts/validate.test.mjs +0 -0
  62. /package/{skills/easysociable-content → content-engine}/scripts/workbench.mjs +0 -0
  63. /package/{skills/easysociable-content → content-engine}/starter/CLAUDE.md +0 -0
  64. /package/{skills/easysociable-content → content-engine}/starter/accounts/README.md +0 -0
  65. /package/{skills/easysociable-content → content-engine}/starter/accounts/_index.md +0 -0
  66. /package/{skills/easysociable-content → content-engine}/starter/accounts/overrides/README.md +0 -0
  67. /package/{skills/easysociable-content → content-engine}/starter/discovery/README.md +0 -0
  68. /package/{skills/easysociable-content → content-engine}/starter/discovery/_index.md +0 -0
  69. /package/{skills/easysociable-content → content-engine}/starter/discovery/_template.md +0 -0
  70. /package/{skills/easysociable-content → content-engine}/starter/engine.json +0 -0
  71. /package/{skills/easysociable-content → content-engine}/starter/exports/README.md +0 -0
  72. /package/{skills/easysociable-content → content-engine}/starter/inbox/README.md +0 -0
  73. /package/{skills/easysociable-content → content-engine}/starter/inbox/_index.md +0 -0
  74. /package/{skills/easysociable-content → content-engine}/starter/inbox/entries/README.md +0 -0
  75. /package/{skills/easysociable-content → content-engine}/starter/platforms/README.md +0 -0
  76. /package/{skills/easysociable-content → content-engine}/starter/platforms/ig.md +0 -0
  77. /package/{skills/easysociable-content → content-engine}/starter/platforms/instagram.md +0 -0
  78. /package/{skills/easysociable-content → content-engine}/starter/platforms/linkedin.md +0 -0
  79. /package/{skills/easysociable-content → content-engine}/starter/platforms/threads.md +0 -0
  80. /package/{skills/easysociable-content → content-engine}/starter/platforms/tiktok.md +0 -0
  81. /package/{skills/easysociable-content → content-engine}/starter/platforms/x.md +0 -0
  82. /package/{skills/easysociable-content → content-engine}/starter/platforms/xiaohongshu.md +0 -0
  83. /package/{skills/easysociable-content → content-engine}/starter/profiles/_index.md +0 -0
  84. /package/{skills/easysociable-content → content-engine}/starter/profiles/default/README.md +0 -0
  85. /package/{skills/easysociable-content → content-engine}/starter/profiles/default/audience.md +0 -0
  86. /package/{skills/easysociable-content → content-engine}/starter/profiles/default/pillars.md +0 -0
  87. /package/{skills/easysociable-content → content-engine}/starter/profiles/default/voice.md +0 -0
  88. /package/{skills/easysociable-content → content-engine}/starter/published/_index.md +0 -0
  89. /package/{skills/easysociable-content → content-engine}/starter/raw/README.md +0 -0
  90. /package/{skills/easysociable-content → content-engine}/starter/raw/_index.md +0 -0
  91. /package/{skills/easysociable-content → content-engine}/starter/runs/README.md +0 -0
  92. /package/{skills/easysociable-content → content-engine}/starter/runs/_index.md +0 -0
  93. /package/{skills/easysociable-content → content-engine}/starter/runs/_template/brief.md +0 -0
  94. /package/{skills/easysociable-content → content-engine}/starter/runs/_template/draft.md +0 -0
  95. /package/{skills/easysociable-content → content-engine}/starter/runs/_template/editor.md +0 -0
  96. /package/{skills/easysociable-content → content-engine}/starter/runs/_template/feedback.md +0 -0
  97. /package/{skills/easysociable-content → content-engine}/starter/runs/_template/idea.md +0 -0
  98. /package/{skills/easysociable-content → content-engine}/starter/runs/_template/pack.md +0 -0
  99. /package/{skills/easysociable-content → content-engine}/starter/runs/_template/packet.md +0 -0
  100. /package/{skills/easysociable-content → content-engine}/starter/runs/_template/rubric.md +0 -0
  101. /package/{skills/easysociable-content → content-engine}/starter/swipe/_index.md +0 -0
  102. /package/{skills/easysociable-content → content-engine}/starter/swipe/_template.md +0 -0
  103. /package/{skills/easysociable-content → content-engine}/starter/topics/README.md +0 -0
  104. /package/{skills/easysociable-content → content-engine}/starter/topics/WATCHLIST.md +0 -0
  105. /package/{skills/easysociable-content → content-engine}/starter/topics/_index.md +0 -0
  106. /package/{skills/easysociable-content → content-engine}/starter/topics/_template-item.md +0 -0
  107. /package/{skills/easysociable-content → content-engine}/starter/topics/items/README.md +0 -0
  108. /package/{skills/easysociable-content → content-engine}/starter/topics/scoring.md +0 -0
  109. /package/{skills/easysociable-content → content-engine}/starter/topics/watchlists/README.md +0 -0
  110. /package/{skills/easysociable-content → content-engine}/starter/topics/watchlists/_shared.md +0 -0
  111. /package/{skills/easysociable-content → content-engine}/starter/topics/watchlists/default.md +0 -0
  112. /package/{skills/easysociable-content → content-engine}/starter/wiki/README.md +0 -0
  113. /package/{skills/easysociable-content → content-engine}/starter/wiki/atoms/_index.md +0 -0
  114. /package/{skills/easysociable-content → content-engine}/starter/wiki/atoms/_template.md +0 -0
  115. /package/{skills/easysociable-content → content-engine}/starter/wiki/claims/_index.md +0 -0
  116. /package/{skills/easysociable-content → content-engine}/starter/wiki/claims/_template.md +0 -0
  117. /package/{skills/easysociable-content → content-engine}/starter/workbench/README.md +0 -0
  118. /package/{skills/easysociable-content → content-engine}/workbench/build.py +0 -0
  119. /package/{skills/easysociable-content → content-engine}/workbench/serve.py +0 -0
  120. /package/{skills/easysociable-content → content-engine}/workbench/template.html +0 -0
@@ -1,40 +0,0 @@
1
- # Content Skill filesystem reference
2
-
3
- The Content Skill does not own a Content CLI. It writes `Content Engine/` on disk and uses the unified `easysociable` command only for hosted Template/Slideshow handoff.
4
-
5
- ## Local workflow
6
-
7
- Ask for a parent directory (or existing engine path). Do not ask language. Do not require Obsidian.
8
-
9
- Do not invent `easysociable-content init/start/doctor`.
10
-
11
- ## Setup
12
-
13
- ```bash
14
- node scripts/setup.mjs --detect --json
15
- node scripts/setup.mjs --root <parent-or-engine> --preview --json
16
- node scripts/setup.mjs --root <parent-or-engine> --apply --json
17
- node scripts/setup.mjs --root <parent-or-engine> --validate --json
18
- node scripts/workbench.mjs start --engine <Content Engine> --json
19
- node scripts/workbench.mjs build --engine <Content Engine> --json
20
- ```
21
-
22
- `--no-open` skips the browser and the workbench server.
23
-
24
- ## Hosted handoff
25
-
26
- ```bash
27
- easysociable templates list --platforms tiktok --json
28
- easysociable slideshows create --file ./runs/<slug>/pack-tiktok.json --json
29
- easysociable slideshows render --id run_xxx --idempotency-key run_xxx-final-1 --json
30
- easysociable slideshows export --id run_xxx --output ./exports/<slug> --json
31
- ```
32
-
33
- Validate before slideshow create:
34
-
35
- ```bash
36
- node scripts/validate-run.mjs --run ./runs/<slug> --require-pack --json
37
- node scripts/validate-pack.mjs --file ./runs/<slug>/pack-tiktok.json --json
38
- ```
39
-
40
- Use unified MCP first when the host exposes it. CLI is the fallback.
@@ -1,42 +0,0 @@
1
- # Contract sync
2
-
3
- Pack validation in this skill mirrors the hosted public contract. When those
4
- contracts change, update this skill in the same PR.
5
-
6
- ## Source of truth
7
-
8
- | Contract | Repository path |
9
- |---|---|
10
- | `content-pack.v1` schema | `packages/template-public-contracts/src/index.ts` → `contentPackSchema` |
11
- | Platform page caps | `slideshowPlatformCaps` in the same file |
12
- | Page roles | `pageRoleSchema` in the same file |
13
-
14
- ## Mirrored in skill
15
-
16
- | Skill file | What to sync |
17
- |---|---|
18
- | `scripts/contracts.mjs` | caps, roles, forbidden keys, validate logic |
19
- | `references/PAGE_PACK.md` | Agent-facing summary + examples |
20
- | `references/PLATFORM_GUIDE.md` | slideshow vs template routing |
21
-
22
- ## Maintainer checklist
23
-
24
- Before merging contract changes:
25
-
26
- 1. Diff `contentPackSchema` / `slideshowPlatformCaps` / `pageRoleSchema`.
27
- 2. Update `contracts.mjs` and `PAGE_PACK.md`.
28
- 3. Run:
29
-
30
- ```bash
31
- node skills/easysociable-content/scripts/validate.test.mjs
32
- node skills/easysociable-content/scripts/fixture.test.mjs
33
- node skills/easysociable-content/scripts/setup.test.mjs
34
- ```
35
-
36
- 4. If caps or roles changed, refresh `fixtures/golden-run-en/pack-tiktok.json` when needed.
37
-
38
- ## Optional hard sync (future)
39
-
40
- Import `contentPackSchema` from `@easysociable/template-public-contracts` in
41
- `validate-pack.mjs` once skill scripts run through the monorepo toolchain. Until
42
- then, `contracts.mjs` is the portable mirror (marked with `ponytail:`).
@@ -1,15 +0,0 @@
1
- # Unified MCP reference
2
-
3
- V1 has one MCP server from the unified EasySociable installer. It owns hosted Template, Image, Profile, Theme, Slideshow and Render tools. This Content Skill does not require a Content MCP.
4
-
5
- Content work stays on disk under `Content Engine/`. Hosted calls use the same Gateway client as the CLI.
6
-
7
- ## Handoff sequence
8
-
9
- 1. After SHIP, write `pack.md` (slideshow) or slot values (single-page).
10
- 2. Slideshow skill writes `content-pack.v1` into the run folder, then `create_slideshow_run`.
11
- 3. Open Studio URL; wait for Save.
12
- 4. After confirmation call `render_slideshow_run`.
13
- 5. Export PNGs into `exports/<run-slug>/`.
14
-
15
- The MCP server must never expose private AST, Binding Maps, RenderPlans, R2 credentials, Directus credentials, Stripe credentials or Local Runtime tokens.
@@ -1,129 +0,0 @@
1
- # PagePack handoff (`content-pack.v1`)
2
-
3
- The Pack is the boundary between semantic content (Content Skill) and visual
4
- composition (Template / Slideshow Skills). Content writes slots and roles;
5
- downstream skills choose Page Templates and render.
6
-
7
- **Source of truth for caps and roles:** `packages/template-public-contracts`
8
- (`contentPackSchema`). This file is the Agent-facing summary.
9
-
10
- ## Schema
11
-
12
- ```json
13
- {
14
- "schemaVersion": "content-pack.v1",
15
- "platform": "tiktok",
16
- "title": "Optional title",
17
- "pages": [
18
- {
19
- "role": "hook",
20
- "slots": { "text_0": "Hook line", "text_1": "Support" },
21
- "pageTemplateId": "tpl_selected_at_handoff"
22
- }
23
- ]
24
- }
25
- ```
26
-
27
- | Field | Required | Notes |
28
- |---|---|---|
29
- | `schemaVersion` | yes | Must be `content-pack.v1` |
30
- | `platform` | yes | See platform table below |
31
- | `title` | no | Display title for Studio |
32
- | `pages` | yes | Ordered array, length within platform caps |
33
- | `pages[].role` | yes | Closed `pageRoles` enum |
34
- | `pages[].slots` | yes | Public slot key → string/number/boolean/null |
35
- | `pages[].pageTemplateId` | yes | Published Page Template selected by Slideshow before `create` |
36
-
37
- ## Forbidden in Pack
38
-
39
- Never include:
40
-
41
- - `deck_template_id` / Deck references
42
- - Template AST, Binding Maps, RenderPlans
43
- - `ContentDocument` / `contentDocumentHash`
44
- - Private gateway credentials or image URLs as slot values (use `imageId` after import)
45
-
46
- ## Platform page caps
47
-
48
- | Platform | Min pages | Max pages | V1 Slideshow |
49
- |---|---:|---:|---|
50
- | `tiktok` | 4 | 35 | yes |
51
- | `instagram` | 2 | 20 | yes |
52
- | `linkedin` | 2 | 300 | yes |
53
- | `threads` | 2 | 20 | yes |
54
- | `xiaohongshu` | — | — | not a Content Pack route in V1; use Template single-page |
55
-
56
- `x` is not a Pack platform. Use Template fill-slots for single-page X graphics.
57
-
58
- ## Page roles (closed set)
59
-
60
- `cover`, `hook`, `setup`, `context`, `value`, `point`, `checklist`, `proof`,
61
- `evidence`, `compare`, `screenshot`, `metric`, `quote`, `steps`, `cta`, `follow`, `recap`
62
-
63
- Pick roles that match the narrative arc. Slideshow maps each page to a published
64
- Page Template with compatible `supportedRoles`.
65
-
66
- ## File naming
67
-
68
- During the run, write vault-native pack markdown:
69
-
70
- ```text
71
- pack.md
72
- pack-<platform>.md
73
- ```
74
-
75
- `content-pack.v1` JSON is created **at Slideshow/Template handoff**, not during draft:
76
-
77
- ```text
78
- pack-<platform>.json
79
- ```
80
-
81
- Example: `pack-tiktok.json`. Pure X text has no pack.
82
-
83
- ## Validation
84
-
85
- ```bash
86
- node scripts/validate-pack.mjs --file ./pack-tiktok.json --platform tiktok --json
87
- ```
88
-
89
- Before Slideshow `create`, also run:
90
-
91
- ```bash
92
- node scripts/validate-pack.mjs --file ./pack-tiktok.json --require-page-template-id --json
93
- ```
94
-
95
- ## Examples
96
-
97
- ### English — TikTok (4 pages, content stage)
98
-
99
- ```json
100
- {
101
- "schemaVersion": "content-pack.v1",
102
- "platform": "tiktok",
103
- "title": "Morning routine tips",
104
- "pages": [
105
- { "role": "hook", "pageTemplateId": "tpl_hook_001", "slots": { "text_0": "Stop scrolling — this changed my mornings" } },
106
- { "role": "value", "pageTemplateId": "tpl_value_001", "slots": { "text_0": "Wake at the same time", "text_1": "No phone for 20 minutes" } },
107
- { "role": "value", "pageTemplateId": "tpl_value_001", "slots": { "text_0": "Move before caffeine", "text_1": "Even 5 minutes counts" } },
108
- { "role": "cta", "pageTemplateId": "tpl_cta_001", "slots": { "text_0": "Save this for tomorrow" } }
109
- ]
110
- }
111
- ```
112
-
113
- ### 中文 — TikTok(4 页,内容阶段)
114
-
115
- ```json
116
- {
117
- "schemaVersion": "content-pack.v1",
118
- "platform": "tiktok",
119
- "title": "晨间习惯三条",
120
- "pages": [
121
- { "role": "hook", "pageTemplateId": "tpl_hook_001", "slots": { "text_0": "别再瞎忙了——我靠这三条稳住早晨" } },
122
- { "role": "value", "pageTemplateId": "tpl_value_001", "slots": { "text_0": "固定起床时间", "text_1": "醒来先别碰手机" } },
123
- { "role": "value", "pageTemplateId": "tpl_value_001", "slots": { "text_0": "喝咖啡前先动一动", "text_1": "五分钟也算数" } },
124
- { "role": "cta", "pageTemplateId": "tpl_cta_001", "slots": { "text_0": "先收藏,明早试" } }
125
- ]
126
- }
127
- ```
128
-
129
- JSON field names and `role` values stay English even when slot copy is 中文.
@@ -1,36 +0,0 @@
1
- # Platform guide
2
-
3
- Use this matrix before opening a run. **Ask** if the user did not name a platform. Multi-select → **N runs**.
4
-
5
- | Platform | Slideshow (V1) | Pack platform key | Page cap (slideshow) | Default path |
6
- |---|---|---|---:|---|
7
- | TikTok | yes | `tiktok` | 4–35 | Slideshow |
8
- | Instagram | yes | `instagram` (`ig`) | 2–20 | Slideshow |
9
- | LinkedIn | yes | `linkedin` | 2–300 | Slideshow |
10
- | Threads | yes | `threads` | 2–20 | Slideshow |
11
- | X | **no** | — (no Pack) | — | Template single-page or text-only |
12
- | Xiaohongshu | **no** (V1) | — | — | Template single-page |
13
-
14
- Craft notes live under `Content Engine/platforms/`. Map: `instagram` → `ig.md`. Read the file before brief/draft/editor.
15
-
16
- ## Routing
17
-
18
- ```text
19
- 1 page → easysociable-template
20
- 2+ pages + slideshow platform → easysociable-slideshow
21
- x → easysociable-template only (if images)
22
- xiaohongshu → easysociable-template until slideshow ships
23
- ```
24
-
25
- ## Canvas hints (for downstream skills)
26
-
27
- | Platform | Typical canvas | Notes |
28
- |---|---|---|
29
- | tiktok | 9:16 @ 1080×1920 | Photo Mode carousel |
30
- | instagram / ig | 4:5 or 1:1 @ 1080 | Feed carousel |
31
- | linkedin | 4:5 or 1:1 | Document-style decks |
32
- | threads | 4:5 or 1:1 | Conversational copy |
33
- | x | 16:9 or 1:1 | Single image post |
34
- | xiaohongshu | 3:4 @ 1080×1440 | See Template `PLATFORM_SPECS` |
35
-
36
- Content Skill does not pick Page Templates — only platform, roles and slot copy. Pack JSON is written at Slideshow/Template handoff, not during draft.
@@ -1,73 +0,0 @@
1
- # Run layout
2
-
3
- Copy `runs/_template/` to `runs/<YYYY-MM-DD-short-slug[-platform]>/`.
4
-
5
- **One folder = one platform.** Same Topic on another network = another folder sharing `topic_id`.
6
-
7
- ```text
8
- Content Engine/runs/<slug>/
9
- ```
10
-
11
- ## Core files
12
-
13
- | File | Purpose |
14
- |---|---|
15
- | `idea.md` | Run id, status, **this** platform, selection (`swipe_id` / `atoms` / `claim_id`) |
16
- | `brief.md` | Angle, constraints, selection why |
17
- | `packet.md` | Writer context (pillar + voice + audience + craft notes) |
18
- | `draft.md` | Copy for **this platform only** |
19
- | `editor.md` | REVISE / APPROVE |
20
- | `rubric.md` | 6 × 0–2; SHIP ≥ 8 |
21
- | `pack.md` | Image deck slots after SHIP (slideshow platforms) |
22
- | `feedback.md` | URL + `win`/`flat`/`loss` after publish |
23
- | `pack-<platform>.json` | Complete `content-pack.v1` — **only at render handoff** |
24
-
25
- ## `idea.md` frontmatter
26
-
27
- ```yaml
28
- ---
29
- run_id: RUN-YYYYMMDD-slug
30
- status: RUN_OPEN
31
- created: YYYY-MM-DD
32
- ---
33
- ```
34
-
35
- Body must include `primary_platform` equal to `platforms` (single value) and the three selection fields. `none` is allowed with why.
36
-
37
- ### File status vs index status
38
-
39
- | `idea.md` | `runs/_index.md` |
40
- |---|---|
41
- | `RUN_OPEN` | `open` |
42
- | `BRIEF_WAIT` | `brief` |
43
- | `DRAFTED` / `EDIT_WAIT` | `draft` |
44
- | `SCORED` | `scored` |
45
- | `READY_TO_POST` | `ready` |
46
- | `PUBLISHED` | `published` |
47
- | `HOLD` / `KILLED` / `SUPERSEDED` | `hold` / `killed` / `superseded` |
48
-
49
- Do not use index status `partial` for new runs.
50
-
51
- ## Validation
52
-
53
- Semantic run (no Pack JSON yet):
54
-
55
- ```bash
56
- node scripts/validate-run.mjs --run <run-dir> --json
57
- ```
58
-
59
- Slideshow handoff (Pack JSON required):
60
-
61
- ```bash
62
- node scripts/validate-run.mjs --run <run-dir> --require-pack --json
63
- node scripts/validate-pack.mjs --file <run-dir>/pack-<platform>.json --platform <platform> --json
64
- ```
65
-
66
- ## Export path
67
-
68
- Final PNGs at the **engine root**, not inside the run folder:
69
-
70
- ```text
71
- Content Engine/exports/<run-slug>/01.png
72
- Content Engine/exports/<run-slug>/<platform>/01.png # optional subfolder
73
- ```
@@ -1,13 +0,0 @@
1
- # Troubleshooting
2
-
3
- No Content CLI, Local API, SQLite, or Obsidian requirement.
4
-
5
- If setup fails, stop before overwriting files. `python3` missing → install Python 3; starter files may already be written.
6
-
7
- If port 8765 is in use, reuse `http://127.0.0.1:8765/workbench/` — do not start a second server. Rebuild with `python3 workbench/build.py`.
8
-
9
- Never overwrite an existing `workbench/template.html`. `--apply` only adds missing files.
10
-
11
- If a run is incomplete, keep existing markdown and report the missing file. `validate-run.mjs` / `validate-pack.mjs` list concrete gaps. Do not auto-migrate an existing engine.
12
-
13
- Deferred features: `workflows/OUT_OF_SCOPE.md`.
@@ -1,40 +0,0 @@
1
- # Engine layout
2
-
3
- The skill creates one English root:
4
-
5
- ```text
6
- <parent>/Content Engine/
7
- ```
8
-
9
- `--root` is the **parent** directory, or the `Content Engine/` path itself.
10
-
11
- ```json
12
- {
13
- "schemaVersion": "content-engine.v1",
14
- "locale": "en",
15
- "root": "Content Engine",
16
- "paths": { "runs": "runs", "exports": "exports", "workbench": "workbench" }
17
- }
18
- ```
19
-
20
- Folders: `accounts`, `inbox`, `swipe`, `topics`, `discovery`, `raw`, `profiles`, `published`, `wiki`, `platforms`, `runs`, `exports`, `workbench`.
21
-
22
- Platform craft files: `x.md`, `ig.md` (`instagram` → `ig.md`), `tiktok.md`, `linkedin.md`, `threads.md`, `xiaohongshu.md`.
23
-
24
- ## Workbench
25
-
26
- Copied from the skill package **only when missing**. Never overwrite an existing `workbench/template.html`.
27
-
28
- ```text
29
- http://127.0.0.1:8765/workbench/
30
- ```
31
-
32
- Rebuild with `python3 workbench/build.py` after markdown writes.
33
-
34
- ## Export path
35
-
36
- ```text
37
- Content Engine/exports/<run-slug>/01.png
38
- ```
39
-
40
- Exports are **not** nested under `runs/<slug>/`. See `references/RUN_LAYOUT.md`.
@@ -1,16 +0,0 @@
1
- # Local voice vs hosted Profile
2
-
3
- | Concept | Where | When | Purpose |
4
- |---|---|---|---|
5
- | **Local voice** | `profiles/<id>/voice.md` | First draft (optional) | Identity + tone for the Agent |
6
- | **Local profile** | `profiles/<id>/` | Multi-brand | Pillars + audience + voice |
7
- | **Hosted Brand Profile** | Gateway (`easysociable profiles …`) | First render | Visual identity: Theme, logo, quotas |
8
-
9
- ## Rules
10
-
11
- 1. **Setup does not create a hosted Profile.**
12
- 2. **Local voice is optional.** Ask once; user may skip.
13
- 3. **Hosted Profile is required for render**, owned by Template/Slideshow skills.
14
- 4. Never store API keys, passwords or Stripe tokens in `profiles/` or `accounts/`.
15
-
16
- When writing `draft.md` or pack slots, read the resolved voice file and audience **core + this platform**.
@@ -1,49 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import { cpSync, existsSync, mkdirSync, rmSync } from 'node:fs'
4
- import { join, relative, resolve, sep } from 'node:path'
5
-
6
- const skillRoot = resolve(new URL('..', import.meta.url).pathname)
7
- const include = ['SKILL.md', 'INSTALL.md', 'scripts', 'references', 'workflows', 'platforms', 'fixtures', 'starter', 'workbench']
8
-
9
- function parseArgs(argv) {
10
- let output = ''
11
- let force = false
12
- for (let i = 0; i < argv.length; i += 1) {
13
- if (argv[i] === '--output') output = argv[++i] ?? ''
14
- else if (argv[i] === '--force') force = true
15
- else if (argv[i] === '--help' || argv[i] === '-h') return { help: true }
16
- else throw new Error(`Unknown argument: ${argv[i]}`)
17
- }
18
- return { output, force }
19
- }
20
-
21
- try {
22
- const options = parseArgs(process.argv.slice(2))
23
- if (options.help) {
24
- process.stdout.write('Usage: node package-skill.mjs --output <destination-dir> [--force]\n')
25
- process.exit(0)
26
- }
27
- if (!options.output) throw new Error('--output is required')
28
-
29
- const dest = resolve(options.output)
30
- const sourceToDest = relative(skillRoot, dest)
31
- const destToSource = relative(dest, skillRoot)
32
- const touchesSource = dest === skillRoot
33
- || (!sourceToDest.startsWith(`..${sep}`) && sourceToDest !== '..')
34
- || (!destToSource.startsWith(`..${sep}`) && destToSource !== '..')
35
- if (touchesSource) throw new Error('--output must be outside the skill source directory')
36
- if (existsSync(dest) && !options.force) throw new Error('Output already exists; pass --force to replace it')
37
- if (existsSync(dest)) rmSync(dest, { recursive: true, force: true })
38
- mkdirSync(dest, { recursive: true })
39
-
40
- for (const name of include) {
41
- cpSync(join(skillRoot, name), join(dest, name), { recursive: true })
42
- }
43
-
44
- process.stdout.write(`Packaged skill → ${dest}\n`)
45
- }
46
- catch (error) {
47
- console.error(error instanceof Error ? error.message : String(error))
48
- process.exitCode = 1
49
- }
@@ -1,200 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import { existsSync, mkdirSync, readdirSync, statSync, writeFileSync } from 'node:fs'
4
- import { homedir } from 'node:os'
5
- import { basename, join, resolve } from 'node:path'
6
- import { ENGINE_ROOT, filesFor } from './starter.mjs'
7
- import { buildWorkbench, ensureWorkbench, python3Bin, startWorkbench } from './workbench.mjs'
8
-
9
- function parseArgs(argv) {
10
- const options = {
11
- root: '', engine: '', apply: false, validate: false, preview: false,
12
- detect: false, noOpen: false, json: false, workbench: false,
13
- }
14
- for (let i = 0; i < argv.length; i += 1) {
15
- const arg = argv[i]
16
- if (arg === '--root') options.root = argv[++i] ?? ''
17
- else if (arg === '--engine') options.engine = argv[++i] ?? ''
18
- else if (arg === '--apply') options.apply = true
19
- else if (arg === '--validate') options.validate = true
20
- else if (arg === '--preview') options.preview = true
21
- else if (arg === '--detect') options.detect = true
22
- else if (arg === '--no-open') options.noOpen = true
23
- else if (arg === '--workbench') options.workbench = true
24
- else if (arg === '--json') options.json = true
25
- else if (arg === '--help' || arg === '-h') options.help = true
26
- else throw new Error(`Unknown argument: ${arg}`)
27
- }
28
- return options
29
- }
30
-
31
- function output(value, json) {
32
- process.stdout.write(json ? `${JSON.stringify(value, null, 2)}\n` : `${value.message ?? value}\n`)
33
- }
34
-
35
- function isDir(path) {
36
- return existsSync(path) && statSync(path).isDirectory()
37
- }
38
-
39
- function isEngine(path) {
40
- return isDir(path) && existsSync(join(path, 'CLAUDE.md')) && isDir(join(path, 'runs'))
41
- }
42
-
43
- function resolveEngine(rootOrEngine) {
44
- const absolute = resolve(rootOrEngine)
45
- if (isEngine(absolute) || basename(absolute) === ENGINE_ROOT) return absolute
46
- return join(absolute, ENGINE_ROOT)
47
- }
48
-
49
- function searchRoots() {
50
- const extra = (process.env.EASYSOCIABLE_ENGINE_SEARCH_ROOTS || '')
51
- .split(process.platform === 'win32' ? ';' : ':')
52
- .map((item) => item.trim())
53
- .filter(Boolean)
54
- const home = homedir()
55
- return [...extra, join(home, 'Documents'), home]
56
- }
57
-
58
- function detectEngines() {
59
- const found = []
60
- for (const root of searchRoots()) {
61
- if (!isDir(root)) continue
62
- const direct = join(root, ENGINE_ROOT)
63
- if (isEngine(direct) || isDir(direct)) found.push(direct)
64
- try {
65
- for (const name of readdirSync(root)) {
66
- const child = join(root, name, ENGINE_ROOT)
67
- if (isDir(child)) found.push(child)
68
- }
69
- }
70
- catch {
71
- continue
72
- }
73
- }
74
- return [...new Set(found)]
75
- }
76
-
77
- function inventory(engine) {
78
- const files = filesFor()
79
- const missing = []
80
- const existing = []
81
- for (const relative of Object.keys(files)) {
82
- const path = join(engine, relative)
83
- ;(existsSync(path) ? existing : missing).push(relative)
84
- }
85
- return {
86
- engine,
87
- engineExists: isDir(engine),
88
- rootName: ENGINE_ROOT,
89
- missing,
90
- existing,
91
- starterComplete: missing.length === 0,
92
- }
93
- }
94
-
95
- function validateRoot(rootOrEngine, { strict = false } = {}) {
96
- const engine = resolveEngine(rootOrEngine)
97
- const parent = resolve(engine, '..')
98
- const errors = []
99
- if (!existsSync(parent) || !statSync(parent).isDirectory()) {
100
- errors.push('Parent directory does not exist')
101
- return { engine, valid: false, errors, created: [] }
102
- }
103
- const result = inventory(engine)
104
- if (existsSync(engine) && !isDir(engine)) errors.push('Content Engine exists but is not a directory')
105
- if (strict) {
106
- if (!result.engineExists) errors.push('Content Engine/ folder does not exist')
107
- else if (result.missing.length > 0) {
108
- errors.push(`Starter incomplete: ${result.missing.length} file(s) missing (use --apply to add only missing files)`)
109
- }
110
- }
111
- return { ...result, valid: errors.length === 0, errors, created: [] }
112
- }
113
-
114
- async function applyStarter(rootOrEngine, noOpen) {
115
- const engine = resolveEngine(rootOrEngine)
116
- const checked = validateRoot(engine)
117
- if (checked.code) return { ...checked, created: [] }
118
- mkdirSync(engine, { recursive: true })
119
- const report = inventory(engine)
120
- const created = []
121
- const files = filesFor()
122
- for (const relative of report.missing) {
123
- const path = join(engine, relative)
124
- mkdirSync(join(path, '..'), { recursive: true })
125
- writeFileSync(path, files[relative], { encoding: 'utf8', flag: 'wx' })
126
- created.push(relative)
127
- }
128
- const workbench = ensureWorkbench(engine)
129
- const python = python3Bin()
130
- if (!python) {
131
- return {
132
- ...validateRoot(engine),
133
- created,
134
- workbench,
135
- action: 'applied',
136
- valid: false,
137
- code: 'PYTHON3_REQUIRED',
138
- errors: ['python3 is required for the workbench. Install Python 3 and retry. Starter files were written; workbench was not started.'],
139
- }
140
- }
141
- const built = buildWorkbench(engine)
142
- let started = { skipped: true, build: built }
143
- if (!noOpen && process.env.EASYSOCIABLE_NO_OPEN !== 'true') {
144
- started = await startWorkbench(engine, { noOpen: false })
145
- }
146
- return { ...validateRoot(engine), created, workbench, workbenchBuild: built, workbenchStart: started, action: 'applied' }
147
- }
148
-
149
- function printHelp() {
150
- process.stdout.write(`Usage:
151
- node setup.mjs --detect [--json]
152
- node setup.mjs --root <parent-or-engine> [--preview|--apply|--validate] [--workbench] [--no-open] [--json]
153
-
154
- English Content Engine/ only. Existing files are never overwritten.
155
- `)
156
- }
157
-
158
- try {
159
- const options = parseArgs(process.argv.slice(2))
160
- if (options.help) {
161
- printHelp()
162
- process.exit(0)
163
- }
164
- if (options.detect) {
165
- output({ action: 'detect', engines: detectEngines() }, options.json)
166
- process.exit(0)
167
- }
168
- const target = options.engine || options.root
169
- if (!target) {
170
- output({ code: 'ROOT_REQUIRED', message: 'Choose a parent directory or Content Engine path with --root.', created: false }, options.json)
171
- process.exitCode = 2
172
- }
173
- else if (options.apply) {
174
- const applied = await applyStarter(target, options.noOpen)
175
- output(applied, options.json)
176
- if (applied.code) process.exitCode = 2
177
- }
178
- else if (options.workbench) {
179
- const engine = resolveEngine(target)
180
- if (!isEngine(engine) && !isDir(engine)) {
181
- output({ code: 'ENGINE_MISSING', message: 'Content Engine/ not found. Run --apply first.', created: false }, options.json)
182
- process.exitCode = 2
183
- }
184
- else {
185
- const started = await startWorkbench(engine, { noOpen: options.noOpen })
186
- output({ action: 'workbench', ...started, engine }, options.json)
187
- if (!started.ok) process.exitCode = 2
188
- }
189
- }
190
- else {
191
- const report = validateRoot(target, { strict: options.validate })
192
- const action = options.validate ? 'validated' : 'preview'
193
- output({ ...report, action, created: [] }, options.json)
194
- if (report.code || (options.validate && !report.valid)) process.exitCode = 2
195
- }
196
- }
197
- catch (error) {
198
- output({ code: 'CONTENT_SETUP_FAILED', message: error instanceof Error ? error.message : String(error), created: false }, true)
199
- process.exitCode = 1
200
- }