@adhamalkhaja/seyola-runtime 0.11.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/LICENSE +56 -0
  2. package/README.md +87 -0
  3. package/dist/adapters/claude-code-local/index.d.ts +60 -0
  4. package/dist/adapters/claude-code-local/index.d.ts.map +1 -0
  5. package/dist/adapters/claude-code-local/index.js +270 -0
  6. package/dist/adapters/claude-code-local/index.js.map +1 -0
  7. package/dist/bundle/index.d.ts +60 -0
  8. package/dist/bundle/index.d.ts.map +1 -0
  9. package/dist/bundle/index.js +989 -0
  10. package/dist/bundle/index.js.map +1 -0
  11. package/dist/cli/index.d.ts +12 -0
  12. package/dist/cli/index.d.ts.map +1 -0
  13. package/dist/cli/index.js +207 -0
  14. package/dist/cli/index.js.map +1 -0
  15. package/dist/compile-plan/budgets.d.ts +23 -0
  16. package/dist/compile-plan/budgets.d.ts.map +1 -0
  17. package/dist/compile-plan/budgets.js +55 -0
  18. package/dist/compile-plan/budgets.js.map +1 -0
  19. package/dist/compile-plan/graph.d.ts +40 -0
  20. package/dist/compile-plan/graph.d.ts.map +1 -0
  21. package/dist/compile-plan/graph.js +114 -0
  22. package/dist/compile-plan/graph.js.map +1 -0
  23. package/dist/compile-plan/index.d.ts +28 -0
  24. package/dist/compile-plan/index.d.ts.map +1 -0
  25. package/dist/compile-plan/index.js +423 -0
  26. package/dist/compile-plan/index.js.map +1 -0
  27. package/dist/compile-plan/registries.d.ts +35 -0
  28. package/dist/compile-plan/registries.d.ts.map +1 -0
  29. package/dist/compile-plan/registries.js +81 -0
  30. package/dist/compile-plan/registries.js.map +1 -0
  31. package/dist/compile-plan/resolver.d.ts +24 -0
  32. package/dist/compile-plan/resolver.d.ts.map +1 -0
  33. package/dist/compile-plan/resolver.js +57 -0
  34. package/dist/compile-plan/resolver.js.map +1 -0
  35. package/dist/compile-plan/types.d.ts +192 -0
  36. package/dist/compile-plan/types.d.ts.map +1 -0
  37. package/dist/compile-plan/types.js +7 -0
  38. package/dist/compile-plan/types.js.map +1 -0
  39. package/dist/doctor/index.d.ts +43 -0
  40. package/dist/doctor/index.d.ts.map +1 -0
  41. package/dist/doctor/index.js +224 -0
  42. package/dist/doctor/index.js.map +1 -0
  43. package/dist/init/index.d.ts +53 -0
  44. package/dist/init/index.d.ts.map +1 -0
  45. package/dist/init/index.js +414 -0
  46. package/dist/init/index.js.map +1 -0
  47. package/dist/lib/ajvSetup.d.ts +30 -0
  48. package/dist/lib/ajvSetup.d.ts.map +1 -0
  49. package/dist/lib/ajvSetup.js +44 -0
  50. package/dist/lib/ajvSetup.js.map +1 -0
  51. package/dist/lib/loadJson.d.ts +21 -0
  52. package/dist/lib/loadJson.d.ts.map +1 -0
  53. package/dist/lib/loadJson.js +43 -0
  54. package/dist/lib/loadJson.js.map +1 -0
  55. package/dist/lib/loadYaml.d.ts +18 -0
  56. package/dist/lib/loadYaml.d.ts.map +1 -0
  57. package/dist/lib/loadYaml.js +41 -0
  58. package/dist/lib/loadYaml.js.map +1 -0
  59. package/dist/lib/paths.d.ts +22 -0
  60. package/dist/lib/paths.d.ts.map +1 -0
  61. package/dist/lib/paths.js +61 -0
  62. package/dist/lib/paths.js.map +1 -0
  63. package/dist/run-plan/index.d.ts +17 -0
  64. package/dist/run-plan/index.d.ts.map +1 -0
  65. package/dist/run-plan/index.js +235 -0
  66. package/dist/run-plan/index.js.map +1 -0
  67. package/dist/run-plan/types.d.ts +53 -0
  68. package/dist/run-plan/types.d.ts.map +1 -0
  69. package/dist/run-plan/types.js +6 -0
  70. package/dist/run-plan/types.js.map +1 -0
  71. package/dist/run-step/contextPacket.d.ts +39 -0
  72. package/dist/run-step/contextPacket.d.ts.map +1 -0
  73. package/dist/run-step/contextPacket.js +213 -0
  74. package/dist/run-step/contextPacket.js.map +1 -0
  75. package/dist/run-step/derivation.d.ts +41 -0
  76. package/dist/run-step/derivation.d.ts.map +1 -0
  77. package/dist/run-step/derivation.js +61 -0
  78. package/dist/run-step/derivation.js.map +1 -0
  79. package/dist/run-step/effectExecutor.d.ts +42 -0
  80. package/dist/run-step/effectExecutor.d.ts.map +1 -0
  81. package/dist/run-step/effectExecutor.js +297 -0
  82. package/dist/run-step/effectExecutor.js.map +1 -0
  83. package/dist/run-step/formatExecutor.d.ts +34 -0
  84. package/dist/run-step/formatExecutor.d.ts.map +1 -0
  85. package/dist/run-step/formatExecutor.js +329 -0
  86. package/dist/run-step/formatExecutor.js.map +1 -0
  87. package/dist/run-step/index.d.ts +23 -0
  88. package/dist/run-step/index.d.ts.map +1 -0
  89. package/dist/run-step/index.js +627 -0
  90. package/dist/run-step/index.js.map +1 -0
  91. package/dist/run-step/inputResolver.d.ts +48 -0
  92. package/dist/run-step/inputResolver.d.ts.map +1 -0
  93. package/dist/run-step/inputResolver.js +268 -0
  94. package/dist/run-step/inputResolver.js.map +1 -0
  95. package/dist/run-step/types.d.ts +123 -0
  96. package/dist/run-step/types.d.ts.map +1 -0
  97. package/dist/run-step/types.js +6 -0
  98. package/dist/run-step/types.js.map +1 -0
  99. package/dist/validate-pack/checks/capabilitiesRegistry.d.ts +3 -0
  100. package/dist/validate-pack/checks/capabilitiesRegistry.d.ts.map +1 -0
  101. package/dist/validate-pack/checks/capabilitiesRegistry.js +83 -0
  102. package/dist/validate-pack/checks/capabilitiesRegistry.js.map +1 -0
  103. package/dist/validate-pack/checks/contextPolicies.d.ts +3 -0
  104. package/dist/validate-pack/checks/contextPolicies.d.ts.map +1 -0
  105. package/dist/validate-pack/checks/contextPolicies.js +40 -0
  106. package/dist/validate-pack/checks/contextPolicies.js.map +1 -0
  107. package/dist/validate-pack/checks/mvkExamples.d.ts +10 -0
  108. package/dist/validate-pack/checks/mvkExamples.d.ts.map +1 -0
  109. package/dist/validate-pack/checks/mvkExamples.js +77 -0
  110. package/dist/validate-pack/checks/mvkExamples.js.map +1 -0
  111. package/dist/validate-pack/checks/requiredFiles.d.ts +3 -0
  112. package/dist/validate-pack/checks/requiredFiles.d.ts.map +1 -0
  113. package/dist/validate-pack/checks/requiredFiles.js +35 -0
  114. package/dist/validate-pack/checks/requiredFiles.js.map +1 -0
  115. package/dist/validate-pack/checks/resolutionPolicy.d.ts +3 -0
  116. package/dist/validate-pack/checks/resolutionPolicy.d.ts.map +1 -0
  117. package/dist/validate-pack/checks/resolutionPolicy.js +88 -0
  118. package/dist/validate-pack/checks/resolutionPolicy.js.map +1 -0
  119. package/dist/validate-pack/checks/schemas.d.ts +16 -0
  120. package/dist/validate-pack/checks/schemas.d.ts.map +1 -0
  121. package/dist/validate-pack/checks/schemas.js +70 -0
  122. package/dist/validate-pack/checks/schemas.js.map +1 -0
  123. package/dist/validate-pack/index.d.ts +25 -0
  124. package/dist/validate-pack/index.d.ts.map +1 -0
  125. package/dist/validate-pack/index.js +95 -0
  126. package/dist/validate-pack/index.js.map +1 -0
  127. package/dist/validate-pack/reporting.d.ts +6 -0
  128. package/dist/validate-pack/reporting.d.ts.map +1 -0
  129. package/dist/validate-pack/reporting.js +40 -0
  130. package/dist/validate-pack/reporting.js.map +1 -0
  131. package/dist/validate-pack/types.d.ts +34 -0
  132. package/dist/validate-pack/types.d.ts.map +1 -0
  133. package/dist/validate-pack/types.js +8 -0
  134. package/dist/validate-pack/types.js.map +1 -0
  135. package/package.json +54 -0
@@ -0,0 +1,989 @@
1
+ /**
2
+ * seyola-runtime bundle — generate a Client Alpha distribution folder.
3
+ *
4
+ * The bundle is meant to be zipped/copied to a friendly tester. The tester
5
+ * unzips, runs setup.ps1 (or setup.sh), and gets a working workspace.
6
+ *
7
+ * What bundle does:
8
+ * 1. Validate the pack (refuse to bundle from a broken pack).
9
+ * 2. Create the output directory if missing.
10
+ * 3. Create empty member-owned folders if missing (preserve if exist).
11
+ * 4. Copy the pack into <out>/.seyola/pack/.
12
+ * 5. Drop a runtime-info note at <out>/.seyola/runtime/.
13
+ * 6. Write <out>/.seyola/version.json with bundle metadata.
14
+ * 7. Write setup.ps1 (Windows) and setup.sh (mac/linux).
15
+ * 8. Write README.md and GETTING-STARTED.md only if missing.
16
+ *
17
+ * What bundle does NOT do:
18
+ * - Run init. Init runs on the tester's machine, via setup script.
19
+ * - Touch .claude/ — init creates .claude/skills + .claude/settings.json
20
+ * using the TESTER's workspace path.
21
+ * - Bundle Node.js or seyola-runtime itself. Setup script checks them
22
+ * and fails loudly with install instructions if missing.
23
+ *
24
+ * Exposed skills (set when init runs on the tester's side):
25
+ * linkedin-writer, brand-voice, audience-profile-builder, story-bank-builder.
26
+ */
27
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, statSync, readdirSync, copyFileSync, rmSync } from "node:fs";
28
+ import { join, resolve, dirname } from "node:path";
29
+ import { validatePack } from "../validate-pack/index.js";
30
+ const APPROVED_SKILLS = ["linkedin-writer", "brand-voice", "audience-profile-builder", "story-bank-builder"];
31
+ const MEMBER_OWNED_DIRS = ["_foundations", "market", "market/audience-profiles", "market/language-bank", "clients", "runs", "output"];
32
+ export async function runBundle(args) {
33
+ const start = Date.now();
34
+ const out = resolve(args.outPath);
35
+ const pack = resolve(args.packPath);
36
+ const bundleName = args.bundleName ?? "seyola-client-alpha";
37
+ const result = {
38
+ exitCode: 0,
39
+ status: "success",
40
+ out_path: out,
41
+ pack_path: pack,
42
+ pack_version: "",
43
+ runtime_version: readRuntimeVersion(),
44
+ bundle_name: bundleName,
45
+ files_written: [],
46
+ runtime_bundled: false,
47
+ warnings: [],
48
+ errors: [],
49
+ duration_ms: 0,
50
+ };
51
+ // 1. Pack must exist.
52
+ if (!existsSync(pack) || !statSync(pack).isDirectory()) {
53
+ result.exitCode = 1;
54
+ result.status = "failed";
55
+ result.errors.push({ code: "pack_not_found", message: `--pack '${pack}' does not exist or is not a directory.` });
56
+ return finalize(args, result, start);
57
+ }
58
+ // 2. Read pack version.
59
+ const manifestPath = join(pack, "manifests", "universal.pack.json");
60
+ if (!existsSync(manifestPath)) {
61
+ result.exitCode = 1;
62
+ result.status = "failed";
63
+ result.errors.push({ code: "pack_manifest_missing", message: `Pack manifest not found at ${manifestPath}.` });
64
+ return finalize(args, result, start);
65
+ }
66
+ try {
67
+ const manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
68
+ result.pack_version = manifest.version ?? "unknown";
69
+ }
70
+ catch {
71
+ result.warnings.push({ code: "pack_manifest_read_warning", message: "Could not read pack version." });
72
+ }
73
+ // 3. Pack must validate clean.
74
+ const validation = await validatePack({ packPath: pack, json: true });
75
+ if (validation.exitCode !== 0) {
76
+ result.exitCode = 1;
77
+ result.status = "failed";
78
+ result.errors.push({ code: "pack_validation_failed", message: `Pack at '${pack}' fails validate-pack. Refusing to bundle from a broken pack.` });
79
+ return finalize(args, result, start);
80
+ }
81
+ // 4. Output dir.
82
+ if (!existsSync(out)) {
83
+ mkdirSync(out, { recursive: true });
84
+ }
85
+ // 5. Member-owned dirs (preserve on rerun). Each gets a .gitkeep so the
86
+ // directory is tracked by git even when empty.
87
+ for (const d of MEMBER_OWNED_DIRS) {
88
+ const abs = join(out, d);
89
+ if (!existsSync(abs))
90
+ mkdirSync(abs, { recursive: true });
91
+ const keep = join(abs, ".gitkeep");
92
+ if (!existsSync(keep)) {
93
+ writeFileSync(keep, "", "utf8");
94
+ result.files_written.push(`${d}/.gitkeep`);
95
+ }
96
+ }
97
+ // 5a. Write .gitignore that protects member-owned folders. The bundle is
98
+ // distributed via git (or zip), so we must not track member-generated
99
+ // content. Always rewritten — system-owned.
100
+ const gitignore = bundleGitignore();
101
+ writeFileSync(join(out, ".gitignore"), gitignore, "utf8");
102
+ result.files_written.push(".gitignore");
103
+ // 6. .seyola/ tree (system-owned, replaced on every bundle).
104
+ const seyolaDir = join(out, ".seyola");
105
+ const seyolaPackDest = join(seyolaDir, "pack");
106
+ const seyolaRuntimeDest = join(seyolaDir, "runtime");
107
+ if (existsSync(seyolaPackDest))
108
+ rmSync(seyolaPackDest, { recursive: true, force: true });
109
+ mkdirSync(seyolaPackDest, { recursive: true });
110
+ copyAlphaPack(pack, seyolaPackDest);
111
+ result.files_written.push(".seyola/pack/ (allowlist copy from " + pack + ")");
112
+ if (existsSync(seyolaRuntimeDest))
113
+ rmSync(seyolaRuntimeDest, { recursive: true, force: true });
114
+ mkdirSync(seyolaRuntimeDest, { recursive: true });
115
+ // If --runtime <path> is supplied, copy a usable runtime artifact in.
116
+ // Otherwise leave a README that says runtime install is manual.
117
+ if (args.runtimePath) {
118
+ const rt = resolve(args.runtimePath);
119
+ const distSrc = join(rt, "dist");
120
+ const pkgSrc = join(rt, "package.json");
121
+ const lockSrc = join(rt, "package-lock.json");
122
+ if (!existsSync(distSrc)) {
123
+ result.warnings.push({
124
+ code: "runtime_dist_missing",
125
+ message: `--runtime '${rt}' has no dist/ directory. Run 'npm run build' in the runtime first. Bundle continuing without an embedded runtime.`,
126
+ });
127
+ writeFileSync(join(seyolaRuntimeDest, "README.md"), runtimeNote(result.runtime_version), "utf8");
128
+ result.files_written.push(".seyola/runtime/README.md");
129
+ }
130
+ else {
131
+ copyDir(distSrc, join(seyolaRuntimeDest, "dist"), {});
132
+ result.files_written.push(".seyola/runtime/dist/");
133
+ if (existsSync(pkgSrc)) {
134
+ copyFileSync(pkgSrc, join(seyolaRuntimeDest, "package.json"));
135
+ result.files_written.push(".seyola/runtime/package.json");
136
+ }
137
+ if (existsSync(lockSrc)) {
138
+ copyFileSync(lockSrc, join(seyolaRuntimeDest, "package-lock.json"));
139
+ result.files_written.push(".seyola/runtime/package-lock.json");
140
+ }
141
+ writeFileSync(join(seyolaRuntimeDest, "README.md"), runtimeBundledNote(result.runtime_version), "utf8");
142
+ result.files_written.push(".seyola/runtime/README.md");
143
+ result.runtime_bundled = true;
144
+ }
145
+ }
146
+ else {
147
+ writeFileSync(join(seyolaRuntimeDest, "README.md"), runtimeNote(result.runtime_version), "utf8");
148
+ result.files_written.push(".seyola/runtime/README.md");
149
+ }
150
+ const versionFile = {
151
+ bundle_name: bundleName,
152
+ workspace_version: "0.1.0",
153
+ pack_version: result.pack_version,
154
+ runtime_version: result.runtime_version,
155
+ runtime_bundled: result.runtime_bundled,
156
+ generated_at: new Date().toISOString(),
157
+ bundle_created_at: new Date().toISOString().slice(0, 10),
158
+ update_channel: "alpha",
159
+ exposed_skills: [...APPROVED_SKILLS],
160
+ note: "Run setup.ps1 (Windows) or setup.sh (mac/linux) to finalize this workspace on your machine.",
161
+ };
162
+ writeFileSync(join(seyolaDir, "version.json"), JSON.stringify(versionFile, null, 2) + "\n", "utf8");
163
+ result.files_written.push(".seyola/version.json");
164
+ // 7. Setup scripts.
165
+ writeFileSync(join(out, "setup.ps1"), setupPowershell(), "utf8");
166
+ result.files_written.push("setup.ps1");
167
+ writeFileSync(join(out, "setup.sh"), setupBash(), { encoding: "utf8", mode: 0o755 });
168
+ result.files_written.push("setup.sh");
169
+ // Windows convenience wrapper that bypasses PowerShell execution-policy
170
+ // restrictions on downloaded files. cmd files don't trigger the restriction.
171
+ writeFileSync(join(out, "setup.cmd"), setupCmd(), "utf8");
172
+ result.files_written.push("setup.cmd");
173
+ // 8. README + GETTING-STARTED — only write if missing.
174
+ const readmePath = join(out, "README.md");
175
+ if (!existsSync(readmePath)) {
176
+ writeFileSync(readmePath, bundleReadme(result.pack_version, result.runtime_version, bundleName), "utf8");
177
+ result.files_written.push("README.md");
178
+ }
179
+ const gsPath = join(out, "GETTING-STARTED.md");
180
+ if (!existsSync(gsPath)) {
181
+ writeFileSync(gsPath, bundleGettingStarted(), "utf8");
182
+ result.files_written.push("GETTING-STARTED.md");
183
+ }
184
+ return finalize(args, result, start);
185
+ }
186
+ // =====================================================================
187
+ // Allowlist-based pack copy for Client Alpha.
188
+ //
189
+ // The bundle ships ONLY what the four approved workflows need:
190
+ // /linkedin-writer, /brand-voice, /audience-profile-builder, /story-bank-builder
191
+ // Plus their runtime dependencies (atom.draft + linkedin-post methodology,
192
+ // the registries, schemas, configs they reference).
193
+ //
194
+ // Strips internal docs, legacy library, unapproved skills, ARCHITECTURE,
195
+ // CHANGELOG, MAP, audits, internal strategy docs.
196
+ // =====================================================================
197
+ const ALPHA_ALLOWED_CAPABILITIES = new Set([
198
+ "atom.draft",
199
+ "artifact.create.social.linkedin-post",
200
+ "artifact.create.analytical.voice-profile",
201
+ "artifact.create.analytical.audience-profile",
202
+ "artifact.create.analytical.story-bank",
203
+ ]);
204
+ const ALPHA_ALLOWED_CONFIG_NAMESPACES = new Set([
205
+ "universal:voice:plain-business@v1",
206
+ "universal:structure:hell-heaven-bridge@v1",
207
+ "universal:structure:default@v1",
208
+ "universal:quality:default@v1",
209
+ "universal:quality:humanizer@v1",
210
+ "universal:quality:cringe-test@v1",
211
+ "universal:quality:would-i-send-this@v1",
212
+ ]);
213
+ function copyAlphaPack(src, dest) {
214
+ // 1. Whole directories that are runtime-essential and contain no IP leak.
215
+ const wholeDirs = [
216
+ ".types",
217
+ ".tags",
218
+ ".substrate",
219
+ ".composer",
220
+ ".context",
221
+ ".harness/schemas",
222
+ ];
223
+ for (const d of wholeDirs) {
224
+ const srcDir = join(src, d);
225
+ if (existsSync(srcDir)) {
226
+ copyDir(srcDir, join(dest, d), {});
227
+ }
228
+ }
229
+ // 2. Selected harness files (policies + linkedin-only examples).
230
+ const harnessFiles = [
231
+ ".harness/routing-policy.json",
232
+ ".harness/planning-policy.json",
233
+ ".harness/README.md",
234
+ ".harness/examples/linkedin-post.task.yaml",
235
+ ".harness/examples/linkedin-post-inline.task.yaml",
236
+ ];
237
+ for (const f of harnessFiles) {
238
+ const srcFile = join(src, f);
239
+ if (existsSync(srcFile)) {
240
+ copyFileWithMkdir(srcFile, join(dest, f));
241
+ }
242
+ }
243
+ // 3. Trimmed registries (capabilities, artifacts, configs).
244
+ trimAndCopyCapabilitiesRegistry(src, dest);
245
+ const allowedArtifactTypes = trimAndCopyArtifactsRegistry(src, dest);
246
+ trimAndCopyConfigsRegistry(src, dest);
247
+ trimAndCopyShapes(src, dest, allowedArtifactTypes);
248
+ // 4. Format adapters and effects.
249
+ // For alpha, /linkedin-writer uses output_format=plain_text (no adapter)
250
+ // and file.export effect. So:
251
+ // - Include effects/ implementation dir (file.export is real and used).
252
+ // - Include .effects/registry.json (whole, file.export is the only entry).
253
+ // - Include .formats/registry.json with no adapters (the gov-proposal
254
+ // adapter is stripped because its owning capability was stripped).
255
+ // - Skip formats/ implementation dir entirely (no adapters in alpha).
256
+ const effectsSrc = join(src, "effects");
257
+ if (existsSync(effectsSrc))
258
+ copyDir(effectsSrc, join(dest, "effects"), {});
259
+ const effectsRegSrc = join(src, ".effects/registry.json");
260
+ if (existsSync(effectsRegSrc)) {
261
+ copyFileWithMkdir(effectsRegSrc, join(dest, ".effects/registry.json"));
262
+ }
263
+ // Trimmed formats registry — empty adapters for alpha.
264
+ trimAndCopyFormatsRegistry(src, dest);
265
+ // 5. Approved skill folders (whole subtrees).
266
+ const approvedSkillFolders = [
267
+ "skills/layer-1/brand-voice",
268
+ "skills/layer-1/audience-profile-builder",
269
+ "skills/layer-1/story-bank-builder",
270
+ "skills/layer-3/linkedin-writer",
271
+ ];
272
+ for (const sk of approvedSkillFolders) {
273
+ const srcSk = join(src, sk);
274
+ if (existsSync(srcSk)) {
275
+ copyDir(srcSk, join(dest, sk), {});
276
+ }
277
+ }
278
+ // 6. Skill dependencies — only the parts of /draft that linkedin-post needs.
279
+ const draftDeps = [
280
+ "skills/layer-2/draft/SKILL.md",
281
+ "skills/layer-2/draft/methodologies/linkedin-post.md",
282
+ ];
283
+ for (const f of draftDeps) {
284
+ const srcFile = join(src, f);
285
+ if (existsSync(srcFile)) {
286
+ copyFileWithMkdir(srcFile, join(dest, f));
287
+ }
288
+ }
289
+ // If draft has a references/ dir, copy it (the SKILL.md references files there).
290
+ const draftRefs = join(src, "skills/layer-2/draft/references");
291
+ if (existsSync(draftRefs)) {
292
+ copyDir(draftRefs, join(dest, "skills/layer-2/draft/references"), {});
293
+ }
294
+ // 7. Manifest (universal pack only).
295
+ const manifestSrc = join(src, "manifests/universal.pack.json");
296
+ if (existsSync(manifestSrc)) {
297
+ copyFileWithMkdir(manifestSrc, join(dest, "manifests/universal.pack.json"));
298
+ }
299
+ // 8. VERSION (small, identifies pack).
300
+ const versionSrc = join(src, "VERSION");
301
+ if (existsSync(versionSrc)) {
302
+ copyFileSync(versionSrc, join(dest, "VERSION"));
303
+ }
304
+ // What is intentionally NOT copied (per docs/SHARING-AND-IP-MODEL.md):
305
+ // docs/ internal strategy + IP docs
306
+ // skills/foundations/ legacy library
307
+ // skills/layer-0/ untyped tour guide
308
+ // skills/layer-1/{capacity,expertise,vault,...} unapproved L1 builders
309
+ // skills/layer-2/{review,frame,research,mine,capture}/ unused atoms
310
+ // skills/layer-2/draft/methodologies/* (except linkedin-post.md)
311
+ // skills/layer-3/* (except linkedin-writer)
312
+ // ARCHITECTURE*.md, MAP.md, CHANGELOG.md, README.md (source-pack one)
313
+ // .skills/inventory.json the audit
314
+ // bin/, knowledge/, seyola-paid-upgrade/, seyola-foundations/
315
+ // formats/ no format adapters used in alpha
316
+ }
317
+ function trimAndCopyCapabilitiesRegistry(src, dest) {
318
+ const srcFile = join(src, ".capabilities/registry.json");
319
+ if (!existsSync(srcFile))
320
+ return;
321
+ const reg = JSON.parse(readFileSync(srcFile, "utf8"));
322
+ const trimmed = {};
323
+ for (const [id, body] of Object.entries(reg.capabilities ?? {})) {
324
+ if (ALPHA_ALLOWED_CAPABILITIES.has(id)) {
325
+ trimmed[id] = body;
326
+ }
327
+ }
328
+ reg.capabilities = trimmed;
329
+ // Strip the verbose _log too — it names internal versions.
330
+ delete reg._log;
331
+ copyFileWithMkdir(srcFile, join(dest, ".capabilities/registry.json"));
332
+ writeFileSync(join(dest, ".capabilities/registry.json"), JSON.stringify(reg, null, 2) + "\n", "utf8");
333
+ }
334
+ function trimAndCopyArtifactsRegistry(src, dest) {
335
+ // Compute artifact types referenced by allowed capabilities.
336
+ const allowed = new Set(["derivation-record"]); // always include
337
+ const capsFile = join(src, ".capabilities/registry.json");
338
+ if (existsSync(capsFile)) {
339
+ const reg = JSON.parse(readFileSync(capsFile, "utf8"));
340
+ for (const [id, cap] of Object.entries(reg.capabilities ?? {})) {
341
+ if (!ALPHA_ALLOWED_CAPABILITIES.has(id))
342
+ continue;
343
+ if (cap.output_artifact_type)
344
+ allowed.add(cap.output_artifact_type);
345
+ for (const t of cap.input_artifact_types ?? [])
346
+ allowed.add(t);
347
+ }
348
+ }
349
+ const srcFile = join(src, ".artifacts/registry.json");
350
+ if (!existsSync(srcFile))
351
+ return allowed;
352
+ const reg = JSON.parse(readFileSync(srcFile, "utf8"));
353
+ const trimmed = {};
354
+ for (const [name, body] of Object.entries(reg.artifact_types ?? {})) {
355
+ if (allowed.has(name))
356
+ trimmed[name] = body;
357
+ }
358
+ reg.artifact_types = trimmed;
359
+ delete reg._log;
360
+ copyFileWithMkdir(srcFile, join(dest, ".artifacts/registry.json"));
361
+ writeFileSync(join(dest, ".artifacts/registry.json"), JSON.stringify(reg, null, 2) + "\n", "utf8");
362
+ return allowed;
363
+ }
364
+ function trimAndCopyConfigsRegistry(src, dest) {
365
+ const srcFile = join(src, ".configs/registry.json");
366
+ if (!existsSync(srcFile))
367
+ return;
368
+ const reg = JSON.parse(readFileSync(srcFile, "utf8"));
369
+ const trimmed = {};
370
+ for (const [ns, body] of Object.entries(reg.configs ?? {})) {
371
+ if (ALPHA_ALLOWED_CONFIG_NAMESPACES.has(ns)) {
372
+ trimmed[ns] = body;
373
+ // Copy the source file too.
374
+ if (body.source_file) {
375
+ const cfgSrc = join(src, body.source_file);
376
+ if (existsSync(cfgSrc)) {
377
+ copyFileWithMkdir(cfgSrc, join(dest, body.source_file));
378
+ }
379
+ }
380
+ }
381
+ }
382
+ reg.configs = trimmed;
383
+ delete reg._log;
384
+ copyFileWithMkdir(srcFile, join(dest, ".configs/registry.json"));
385
+ writeFileSync(join(dest, ".configs/registry.json"), JSON.stringify(reg, null, 2) + "\n", "utf8");
386
+ }
387
+ function trimAndCopyFormatsRegistry(src, dest) {
388
+ const srcFile = join(src, ".formats/registry.json");
389
+ if (!existsSync(srcFile))
390
+ return;
391
+ const reg = JSON.parse(readFileSync(srcFile, "utf8"));
392
+ // Alpha ships with no format adapters — clear the adapters dict but keep
393
+ // the registry shape so the runtime's required-files check passes.
394
+ reg.adapters = {};
395
+ delete reg._log;
396
+ copyFileWithMkdir(srcFile, join(dest, ".formats/registry.json"));
397
+ writeFileSync(join(dest, ".formats/registry.json"), JSON.stringify(reg, null, 2) + "\n", "utf8");
398
+ }
399
+ function trimAndCopyShapes(src, dest, allowedArtifactTypes) {
400
+ // Shapes are needed for: every artifact type used + the type-family shapes
401
+ // referenced by the type registry (voice, structure, audience, quality, format).
402
+ const familyShapes = ["voice", "structure", "audience", "quality", "format"];
403
+ const shapeFiles = new Set(familyShapes);
404
+ for (const t of allowedArtifactTypes)
405
+ shapeFiles.add(t);
406
+ const srcDir = join(src, ".shapes");
407
+ if (!existsSync(srcDir))
408
+ return;
409
+ for (const entry of readdirSync(srcDir, { withFileTypes: true })) {
410
+ if (!entry.isFile() || !entry.name.endsWith(".json"))
411
+ continue;
412
+ const baseName = entry.name.replace(/\.json$/, "");
413
+ if (shapeFiles.has(baseName)) {
414
+ copyFileWithMkdir(join(srcDir, entry.name), join(dest, ".shapes", entry.name));
415
+ }
416
+ }
417
+ }
418
+ function copyFileWithMkdir(src, dest) {
419
+ mkdirSync(dirname(dest), { recursive: true });
420
+ copyFileSync(src, dest);
421
+ }
422
+ function copyDir(src, dest, opts) {
423
+ const exclude = new Set(opts.excludeRel ?? []);
424
+ if (!existsSync(dest))
425
+ mkdirSync(dest, { recursive: true });
426
+ const entries = readdirSync(src, { withFileTypes: true });
427
+ for (const entry of entries) {
428
+ if (exclude.has(entry.name))
429
+ continue;
430
+ const s = join(src, entry.name);
431
+ const d = join(dest, entry.name);
432
+ if (entry.isDirectory()) {
433
+ copyDir(s, d, opts);
434
+ }
435
+ else if (entry.isFile()) {
436
+ mkdirSync(dirname(d), { recursive: true });
437
+ copyFileSync(s, d);
438
+ }
439
+ }
440
+ }
441
+ function readRuntimeVersion() {
442
+ try {
443
+ const here = dirname(new URL(import.meta.url).pathname.replace(/^\/([A-Za-z]:)/, "$1"));
444
+ for (const candidate of [resolve(here, "../../package.json"), resolve(here, "../../../package.json")]) {
445
+ try {
446
+ const pkg = JSON.parse(readFileSync(candidate, "utf8"));
447
+ if (pkg.version)
448
+ return pkg.version;
449
+ }
450
+ catch {
451
+ // try next
452
+ }
453
+ }
454
+ }
455
+ catch {
456
+ // fall through
457
+ }
458
+ return "unknown";
459
+ }
460
+ function setupPowershell() {
461
+ return `# Seyola Client Alpha — setup script (Windows / PowerShell)
462
+ # Run from inside the bundle folder: ./setup.ps1
463
+
464
+ $ErrorActionPreference = "Stop"
465
+
466
+ Write-Host ""
467
+ Write-Host "Seyola Client Alpha setup" -ForegroundColor Cyan
468
+ Write-Host "============================="
469
+ Write-Host ""
470
+
471
+ # 1. Node check
472
+ Write-Host "Checking Node.js..." -NoNewline
473
+ try {
474
+ $nodeVersion = node --version 2>&1
475
+ if ($nodeVersion -match "v(\\d+)") {
476
+ $major = [int]$Matches[1]
477
+ if ($major -lt 20) {
478
+ Write-Host " FAIL" -ForegroundColor Red
479
+ Write-Host " Node.js 20 or higher is required. Found: $nodeVersion"
480
+ Write-Host " Install Node 20+ from https://nodejs.org/, then rerun this script."
481
+ exit 1
482
+ }
483
+ Write-Host " ok ($nodeVersion)" -ForegroundColor Green
484
+ } else {
485
+ throw "Could not parse Node version"
486
+ }
487
+ } catch {
488
+ Write-Host " FAIL" -ForegroundColor Red
489
+ Write-Host " Node.js is not installed or not on PATH."
490
+ Write-Host " Install Node 20+ from https://nodejs.org/, then rerun this script."
491
+ exit 1
492
+ }
493
+
494
+ # 2. Claude Code check
495
+ Write-Host "Checking Claude Code..." -NoNewline
496
+ try {
497
+ $claudeVersion = claude --version 2>&1
498
+ Write-Host " ok ($claudeVersion)" -ForegroundColor Green
499
+ } catch {
500
+ Write-Host " WARN" -ForegroundColor Yellow
501
+ Write-Host " Claude Code is not detected on PATH."
502
+ Write-Host " Install from https://claude.com/claude-code, authenticate (run claude once), then rerun this script."
503
+ Write-Host " Continuing anyway so you can finish setup; the workspace will work once Claude Code is installed."
504
+ }
505
+
506
+ # 3. seyola-runtime check
507
+ Write-Host "Checking seyola-runtime..." -NoNewline
508
+ $rtFound = $false
509
+ try {
510
+ $rtVersion = seyola-runtime --version 2>&1
511
+ Write-Host " ok ($rtVersion, global)" -ForegroundColor Green
512
+ $rtFound = $true
513
+ } catch {
514
+ Write-Host " not on PATH; trying bundled runtime..." -ForegroundColor Yellow
515
+ }
516
+
517
+ if (-not $rtFound) {
518
+ $bundledRuntime = Join-Path (Get-Location).Path ".seyola/runtime"
519
+ $bundledDist = Join-Path $bundledRuntime "dist/cli/index.js"
520
+ if (Test-Path $bundledDist) {
521
+ Write-Host "Installing bundled runtime from .seyola/runtime/ ..." -ForegroundColor Cyan
522
+ Push-Location $bundledRuntime
523
+ npm install --omit=dev --silent
524
+ if ($LASTEXITCODE -ne 0) {
525
+ Write-Host "npm install failed in .seyola/runtime/." -ForegroundColor Red
526
+ Pop-Location
527
+ exit 1
528
+ }
529
+ npm link --silent 2>&1 | Out-Null
530
+ if ($LASTEXITCODE -ne 0) {
531
+ Write-Host "npm link failed. You may need elevated permissions." -ForegroundColor Red
532
+ Pop-Location
533
+ exit 1
534
+ }
535
+ Pop-Location
536
+ try {
537
+ $rtVersion = seyola-runtime --version 2>&1
538
+ Write-Host " ok ($rtVersion, bundled)" -ForegroundColor Green
539
+ $rtFound = $true
540
+ } catch {
541
+ Write-Host " installed but seyola-runtime still not on PATH. Open a new terminal and rerun." -ForegroundColor Red
542
+ exit 1
543
+ }
544
+ } else {
545
+ Write-Host " no bundled runtime found at .seyola/runtime/dist/." -ForegroundColor Red
546
+ Write-Host " Reach out to the Seyola maintainer for an updated bundle that includes the runtime."
547
+ exit 1
548
+ }
549
+ }
550
+
551
+ # 4. Run init against this folder.
552
+ $workspace = (Get-Location).Path
553
+ $pack = Join-Path $workspace ".seyola/pack"
554
+ Write-Host ""
555
+ Write-Host "Initializing workspace at $workspace" -ForegroundColor Cyan
556
+ seyola-runtime init --workspace "$workspace" --pack "$pack"
557
+ if ($LASTEXITCODE -ne 0) {
558
+ Write-Host "init failed. See output above." -ForegroundColor Red
559
+ exit 1
560
+ }
561
+
562
+ # 5. Run doctor.
563
+ Write-Host ""
564
+ Write-Host "Running health check..." -ForegroundColor Cyan
565
+ seyola-runtime doctor --workspace "$workspace"
566
+
567
+ Write-Host ""
568
+ Write-Host "Setup complete." -ForegroundColor Green
569
+ Write-Host ""
570
+ Write-Host "Next steps:"
571
+ Write-Host " 1. Run: claude"
572
+ Write-Host " 2. Type: /linkedin-writer"
573
+ Write-Host ""
574
+ Write-Host "See GETTING-STARTED.md for the full first-run flow."
575
+ Write-Host ""
576
+ `;
577
+ }
578
+ function setupCmd() {
579
+ return `@echo off
580
+ REM Seyola Client Alpha - Windows convenience wrapper.
581
+ REM
582
+ REM Why this file exists:
583
+ REM When you download Seyola as a zip from GitHub, Windows marks every
584
+ REM file inside as "potentially unsafe" (zone marker). PowerShell's
585
+ REM default execution policy then refuses to run setup.ps1 directly.
586
+ REM This wrapper invokes PowerShell with -ExecutionPolicy Bypass so the
587
+ REM setup runs without changing your global PowerShell settings.
588
+ REM
589
+ REM How to run:
590
+ REM - Double-click setup.cmd, OR
591
+ REM - From cmd / PowerShell, type: setup.cmd
592
+ REM
593
+ REM Either way, it calls setup.ps1 with the right policy flag.
594
+
595
+ powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0setup.ps1" %*
596
+ exit /B %ERRORLEVEL%
597
+ `;
598
+ }
599
+ function setupBash() {
600
+ return `#!/usr/bin/env bash
601
+ # Seyola Client Alpha — setup script (mac/linux)
602
+ # Run from inside the bundle folder: ./setup.sh
603
+
604
+ set -e
605
+
606
+ echo ""
607
+ echo "Seyola Client Alpha setup"
608
+ echo "========================="
609
+ echo ""
610
+
611
+ # 1. Node check
612
+ printf "Checking Node.js... "
613
+ if ! command -v node >/dev/null 2>&1; then
614
+ echo "FAIL"
615
+ echo " Node.js is not installed or not on PATH."
616
+ echo " Install Node 20+ from https://nodejs.org/, then rerun this script."
617
+ exit 1
618
+ fi
619
+ NODE_VERSION=$(node --version)
620
+ NODE_MAJOR=$(echo "$NODE_VERSION" | sed 's/v\\([0-9]*\\).*/\\1/')
621
+ if [ "$NODE_MAJOR" -lt 20 ]; then
622
+ echo "FAIL"
623
+ echo " Node.js 20 or higher is required. Found: $NODE_VERSION"
624
+ echo " Install Node 20+ from https://nodejs.org/, then rerun this script."
625
+ exit 1
626
+ fi
627
+ echo "ok ($NODE_VERSION)"
628
+
629
+ # 2. Claude Code check
630
+ printf "Checking Claude Code... "
631
+ if command -v claude >/dev/null 2>&1; then
632
+ CLAUDE_VERSION=$(claude --version 2>&1 || echo "unknown")
633
+ echo "ok ($CLAUDE_VERSION)"
634
+ else
635
+ echo "WARN"
636
+ echo " Claude Code is not detected on PATH."
637
+ echo " Install from https://claude.com/claude-code, authenticate (run claude once), then rerun this script."
638
+ echo " Continuing anyway."
639
+ fi
640
+
641
+ # 3. seyola-runtime check (global first, bundled fallback)
642
+ printf "Checking seyola-runtime... "
643
+ if command -v seyola-runtime >/dev/null 2>&1; then
644
+ RT_VERSION=$(seyola-runtime --version 2>&1)
645
+ echo "ok ($RT_VERSION, global)"
646
+ else
647
+ echo "not on PATH; trying bundled runtime..."
648
+ BUNDLED_RUNTIME="$(pwd)/.seyola/runtime"
649
+ if [ -f "$BUNDLED_RUNTIME/dist/cli/index.js" ]; then
650
+ echo "Installing bundled runtime from .seyola/runtime/ ..."
651
+ (cd "$BUNDLED_RUNTIME" && npm install --omit=dev --silent && npm link --silent)
652
+ if ! command -v seyola-runtime >/dev/null 2>&1; then
653
+ echo " installed but seyola-runtime still not on PATH. Open a new terminal and rerun."
654
+ exit 1
655
+ fi
656
+ RT_VERSION=$(seyola-runtime --version 2>&1)
657
+ echo " ok ($RT_VERSION, bundled)"
658
+ else
659
+ echo " no bundled runtime found at .seyola/runtime/dist/."
660
+ echo " Reach out to the Seyola maintainer for an updated bundle that includes the runtime."
661
+ exit 1
662
+ fi
663
+ fi
664
+
665
+ # 4. Run init.
666
+ WORKSPACE=$(pwd)
667
+ PACK="$WORKSPACE/.seyola/pack"
668
+ echo ""
669
+ echo "Initializing workspace at $WORKSPACE"
670
+ seyola-runtime init --workspace "$WORKSPACE" --pack "$PACK"
671
+
672
+ # 5. Run doctor.
673
+ echo ""
674
+ echo "Running health check..."
675
+ seyola-runtime doctor --workspace "$WORKSPACE"
676
+
677
+ echo ""
678
+ echo "Setup complete."
679
+ echo ""
680
+ echo "Next steps:"
681
+ echo " 1. Run: claude"
682
+ echo " 2. Type: /linkedin-writer"
683
+ echo ""
684
+ echo "See GETTING-STARTED.md for the full first-run flow."
685
+ echo ""
686
+ `;
687
+ }
688
+ function bundleGitignore() {
689
+ return `# Member-owned folders. The repo ships empty placeholders (.gitkeep).
690
+ # Member-generated content stays local — never committed, never overwritten.
691
+ _foundations/*
692
+ !_foundations/.gitkeep
693
+
694
+ market/*
695
+ !market/.gitkeep
696
+
697
+ clients/*
698
+ !clients/.gitkeep
699
+
700
+ runs/*
701
+ !runs/.gitkeep
702
+
703
+ output/*
704
+ !output/.gitkeep
705
+
706
+ # OS / editor noise
707
+ .DS_Store
708
+ Thumbs.db
709
+ *.swp
710
+ *.swo
711
+ *~
712
+ .idea/
713
+ .vscode/
714
+
715
+ # Node
716
+ node_modules/
717
+
718
+ # Misc
719
+ .env
720
+ .env.local
721
+ `;
722
+ }
723
+ function runtimeNote(version) {
724
+ return `# Runtime placeholder
725
+
726
+ This bundle does NOT include a built runtime. The setup script assumes \`seyola-runtime\` (v${version} or compatible) is installed globally on the tester's machine via \`npm link\` or a published package.
727
+
728
+ Setup scripts will fail with a clear instruction if the runtime is missing.
729
+ `;
730
+ }
731
+ function runtimeBundledNote(version) {
732
+ return `# Bundled runtime (v${version})
733
+
734
+ This bundle ships a built copy of \`seyola-runtime\` so the tester does not need to clone the runtime source repo separately.
735
+
736
+ The setup script will:
737
+ 1. Check whether \`seyola-runtime\` is already installed globally. If yes, use that.
738
+ 2. Otherwise, run \`npm install --omit=dev\` inside this directory and link it.
739
+
740
+ Contents:
741
+ - \`dist/\` — compiled CLI (TypeScript output).
742
+ - \`package.json\` — declares the dependencies.
743
+ - \`package-lock.json\` — pinned dependency versions.
744
+
745
+ If you want to update or rebuild the runtime, replace the contents of this directory with a new build artifact and rerun setup.
746
+ `;
747
+ }
748
+ function bundleReadme(packVersion, runtimeVersion, bundleName) {
749
+ return `# ${bundleName}
750
+
751
+ Seyola Client Alpha bundle.
752
+
753
+ - Pack version: ${packVersion}
754
+ - Runtime version: ${runtimeVersion}
755
+ - Channel: alpha
756
+
757
+ ## To use this bundle
758
+
759
+ The most reliable path on Windows is to clone via git (avoids "downloaded from the internet" zone markers that Smart App Control and PowerShell's execution policy use to block scripts) OR to run the runtime commands directly without a script.
760
+
761
+ ### Path A — Manual commands (most reliable on Windows)
762
+
763
+ This works around Smart App Control + execution policy entirely. From inside the unzipped folder, in any terminal:
764
+
765
+ \`\`\`
766
+ seyola-runtime init --workspace . --pack ./.seyola/pack
767
+ seyola-runtime doctor --workspace .
768
+ claude
769
+ \`\`\`
770
+
771
+ Three commands. \`seyola-runtime\` is an installed Node binary, so Windows Smart App Control doesn't block it.
772
+
773
+ ### Path B — Git clone instead of zip download
774
+
775
+ \`\`\`
776
+ git clone https://github.com/seyola-community/seyola-paid.git my-seyola
777
+ cd my-seyola
778
+ \`\`\`
779
+
780
+ Then run Path A's commands, or try the scripts below.
781
+
782
+ ### Path C — Setup scripts (try if A or B felt fiddly)
783
+
784
+ Scripts inside zips downloaded from GitHub are often blocked by Windows. If they work for you, great:
785
+
786
+ - **Windows:** double-click \`setup.cmd\`, or run \`setup.cmd\` from any terminal. If blocked: right-click → Properties → Unblock → OK.
787
+ - **PowerShell direct:** \`powershell -ExecutionPolicy Bypass -File .\\setup.ps1\` — bypasses execution policy but NOT Smart App Control.
788
+ - **mac / linux:** \`bash setup.sh\` (no Windows blocking issues).
789
+
790
+ If Smart App Control or execution policy is still blocking on Windows, fall back to Path A.
791
+
792
+ The setup script:
793
+
794
+ 1. Checks that Node 20+, Claude Code, and \`seyola-runtime\` are on PATH.
795
+ 2. Runs \`seyola-runtime init\` against this folder.
796
+ 3. Runs \`seyola-runtime doctor\` to verify health.
797
+ 4. Tells you what to do next.
798
+
799
+ After setup completes successfully:
800
+
801
+ \`\`\`
802
+ claude
803
+ \`\`\`
804
+
805
+ Then type \`/linkedin-writer\` in the chat.
806
+
807
+ For detailed steps and what each folder is for, see \`GETTING-STARTED.md\`.
808
+
809
+ ## What's in this folder
810
+
811
+ - \`.seyola/\` — system parts. Replaced on update. Do not edit.
812
+ - \`.claude/\` — slash commands and settings. Generated by setup. Do not edit.
813
+ - \`_foundations/\`, \`market/\`, \`clients/\`, \`runs/\`, \`output/\` — yours. Never overwritten on update.
814
+
815
+ ## Health check
816
+
817
+ Any time:
818
+
819
+ \`\`\`
820
+ seyola-runtime doctor --workspace .
821
+ \`\`\`
822
+ `;
823
+ }
824
+ function bundleGettingStarted() {
825
+ return `# Getting Started with Seyola — Client Alpha
826
+
827
+ This is your Seyola workspace. Everything you create stays here.
828
+
829
+ ## Step 1: Setup
830
+
831
+ Open this folder in a terminal. The reliable Windows path is to run the runtime commands directly (the setup scripts can be blocked by Windows security on downloaded files — see notes below).
832
+
833
+ ### macOS / Linux
834
+
835
+ \`\`\`
836
+ bash setup.sh
837
+ \`\`\`
838
+
839
+ ### Windows — recommended path (manual commands, most reliable)
840
+
841
+ \`\`\`
842
+ seyola-runtime init --workspace . --pack ./.seyola/pack
843
+ seyola-runtime doctor --workspace .
844
+ \`\`\`
845
+
846
+ Then continue to Step 2.
847
+
848
+ ### Windows — try the script (sometimes works)
849
+
850
+ Double-click \`setup.cmd\`, or from a terminal:
851
+
852
+ \`\`\`
853
+ setup.cmd
854
+ \`\`\`
855
+
856
+ If Windows says "this app was blocked" or "not digitally signed":
857
+ - Right-click \`setup.cmd\` → **Properties** → check **Unblock** → **OK** → double-click again.
858
+ - Or fall back to the manual commands above.
859
+
860
+ > **Why scripts get blocked on Windows.** Files downloaded inside a zip get tagged as "potentially unsafe" by Windows. PowerShell's execution policy blocks unsigned scripts with that tag, and Windows 11's Smart App Control blocks dangerous file extensions (\`.cmd\`, \`.ps1\`, \`.bat\`) entirely. The manual command path sidesteps all of that — \`seyola-runtime\` is a regular installed Node binary that Windows trusts.
861
+
862
+ The setup script checks prerequisites and finalizes the workspace. If anything is missing (Node, Claude Code, or the runtime), it tells you exactly what to install.
863
+
864
+ ## Step 2: Open Claude Code
865
+
866
+ \`\`\`
867
+ claude
868
+ \`\`\`
869
+
870
+ Claude Code launches in this folder and picks up the slash commands.
871
+
872
+ ## Step 3: Build your voice profile (~30 minutes)
873
+
874
+ \`\`\`
875
+ /brand-voice
876
+ \`\`\`
877
+
878
+ Interactive interview. Output: \`_foundations/voice-profile.md\`. Every drafting workflow reads this. Run it first.
879
+
880
+ ## Step 4: Build your audience profile (~20 minutes)
881
+
882
+ \`\`\`
883
+ /audience-profile-builder
884
+ \`\`\`
885
+
886
+ Interactive. One profile per session. Output: \`market/audience-profiles/[name].md\`.
887
+
888
+ ## Step 5: Build your story bank (~30-45 minutes)
889
+
890
+ \`\`\`
891
+ /story-bank-builder
892
+ \`\`\`
893
+
894
+ Interactive. Surfaces 5-15 signature stories. Output: \`_foundations/story-bank.md\`.
895
+
896
+ ## Step 6: Write a LinkedIn post
897
+
898
+ \`\`\`
899
+ /linkedin-writer
900
+ \`\`\`
901
+
902
+ Paste an idea or topic. The runtime drafts ONE post in your voice using the Hell-Heaven-Bridge structure. Outputs land in \`runs/run-YYYY-MM-DD-li<NN>/\` and \`output/socials/\`.
903
+
904
+ ## What's mine vs what's the system
905
+
906
+ | Folder | Owner | Notes |
907
+ |---|---|---|
908
+ | \`_foundations/\` | yours | Voice profile, story bank. |
909
+ | \`market/\` | yours | Audience profiles, language bank. |
910
+ | \`clients/\` | yours | Per-client engagement folders. |
911
+ | \`runs/\` | yours | Each workflow run gets a folder. |
912
+ | \`output/\` | yours | Final exports. |
913
+ | \`.seyola/\` | system | Replaced on update. Do not edit. |
914
+ | \`.claude/\` | system | Regenerated on update. Do not edit. |
915
+
916
+ ## Health check anytime
917
+
918
+ \`\`\`
919
+ seyola-runtime doctor --workspace .
920
+ \`\`\`
921
+
922
+ If anything's wrong, this command tells you what.
923
+
924
+ ## Slash commands available in this Alpha
925
+
926
+ - \`/brand-voice\`
927
+ - \`/audience-profile-builder\`
928
+ - \`/story-bank-builder\`
929
+ - \`/linkedin-writer\`
930
+
931
+ That's the complete loop for the Alpha. More workflows ship in later releases.
932
+
933
+ ## When something feels wrong
934
+
935
+ If a post doesn't sound like you, the most common cause is: the voice profile hasn't been built yet, or the audience profile is missing. Run \`/brand-voice\` and \`/audience-profile-builder\` first; the difference is usually large.
936
+
937
+ If the wrapper hangs at preflight, check that \`seyola-runtime --version\` works from this folder. If not, rerun the setup script.
938
+
939
+ ## Reporting issues during Alpha
940
+
941
+ This is a friendly-tester release. If something breaks:
942
+
943
+ 1. Run \`seyola-runtime doctor --workspace .\` and capture the output.
944
+ 2. Note which slash command was invoked and what idea/input you provided.
945
+ 3. Share both with the developer.
946
+ `;
947
+ }
948
+ function finalize(args, result, start) {
949
+ result.duration_ms = Date.now() - start;
950
+ if (args.json) {
951
+ process.stdout.write(JSON.stringify(result, null, 2) + "\n");
952
+ }
953
+ else {
954
+ process.stderr.write(formatHuman(result));
955
+ }
956
+ return result;
957
+ }
958
+ function formatHuman(result) {
959
+ const lines = [];
960
+ lines.push("");
961
+ lines.push(`seyola-runtime bundle: status=${result.status}, exitCode=${result.exitCode}`);
962
+ lines.push(` bundle_name: ${result.bundle_name}`);
963
+ lines.push(` out: ${result.out_path}`);
964
+ lines.push(` pack: ${result.pack_path}`);
965
+ lines.push(` pack_version: ${result.pack_version}`);
966
+ lines.push(` runtime_version: ${result.runtime_version}`);
967
+ lines.push(` duration: ${result.duration_ms}ms`);
968
+ if (result.files_written.length > 0) {
969
+ lines.push("");
970
+ lines.push(" written:");
971
+ for (const f of result.files_written)
972
+ lines.push(` + ${f}`);
973
+ }
974
+ if (result.warnings.length > 0) {
975
+ lines.push("");
976
+ lines.push(" warnings:");
977
+ for (const w of result.warnings)
978
+ lines.push(` [${w.code}] ${w.message}`);
979
+ }
980
+ if (result.errors.length > 0) {
981
+ lines.push("");
982
+ lines.push(" errors:");
983
+ for (const e of result.errors)
984
+ lines.push(` [${e.code}] ${e.message}`);
985
+ }
986
+ lines.push("");
987
+ return lines.join("\n");
988
+ }
989
+ //# sourceMappingURL=index.js.map