@easysociable/cli 0.1.9 → 0.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -53,6 +53,7 @@ unless you pass `--sync-workbench` (pulls from the public core checkout /
53
53
  | Command | Purpose |
54
54
  |---------|---------|
55
55
  | `easysociable engine init [--root] [--yes] [--serve]` | Clone public core into `Content Engine/` (no overwrite) |
56
+ | `easysociable engine update [--engine] [--yes]` | Sync core rules from the public template; preview first, apply with `--yes`. Never touches vault data |
56
57
  | `easysociable engine serve [--engine] [--no-open] [--sync-workbench]` | Rebuild + start on `:8765` |
57
58
  | `easysociable engine build [--engine] [--sync-workbench]` | Rebuild `workbench/index.html` |
58
59
  | `easysociable engine detect` | Find engines under search roots |
@@ -32645,7 +32645,8 @@ import {
32645
32645
  readdirSync,
32646
32646
  readFileSync as readFileSync2,
32647
32647
  rmSync,
32648
- statSync
32648
+ statSync,
32649
+ writeFileSync as writeFileSync2
32649
32650
  } from "fs";
32650
32651
  import net from "net";
32651
32652
  import { homedir as homedir2 } from "os";
@@ -33002,6 +33003,121 @@ async function initEngine(rootOrEngine, moduleUrl, {
33002
33003
  source: contentEngineRepoUrl()
33003
33004
  };
33004
33005
  }
33006
+ var CORE_REFRESH_FILES = /* @__PURE__ */ new Set(["CLAUDE.md", "LAYOUT.md", "topics/scoring.md"]);
33007
+ var CORE_ADD_ONLY_FILES = /* @__PURE__ */ new Set(["media/_index.md", "media/README.md", "profiles/default/brand.md"]);
33008
+ function classifyCoreFile(rel) {
33009
+ const parts = rel.split("/");
33010
+ if (parts[0] === ".git")
33011
+ return "skip";
33012
+ if (CORE_ADD_ONLY_FILES.has(rel))
33013
+ return "add";
33014
+ if (CORE_REFRESH_FILES.has(rel))
33015
+ return "refresh";
33016
+ if (parts[0] === "workbench")
33017
+ return "refresh";
33018
+ if (parts[0] === "platforms" && rel.endsWith(".md"))
33019
+ return "refresh";
33020
+ if (basename(rel) === "_template.md" || parts.includes("_template"))
33021
+ return "refresh";
33022
+ return "skip";
33023
+ }
33024
+ function walkCoreFiles(core, relDir = "") {
33025
+ const out = [];
33026
+ const absDir = join3(core, relDir);
33027
+ if (!isDir(absDir))
33028
+ return out;
33029
+ for (const name of readdirSync(absDir)) {
33030
+ if (name === ".git" || name === ".DS_Store")
33031
+ continue;
33032
+ const rel = relDir ? `${relDir}/${name}` : name;
33033
+ if (isDir(join3(core, rel)))
33034
+ out.push(...walkCoreFiles(core, rel));
33035
+ else
33036
+ out.push(rel);
33037
+ }
33038
+ return out;
33039
+ }
33040
+ function mergeEngineJson(engine, core) {
33041
+ const engPath = join3(engine, "engine.json");
33042
+ const corePath = join3(core, "engine.json");
33043
+ if (!existsSync3(engPath) || !existsSync3(corePath))
33044
+ return [];
33045
+ let eng;
33046
+ let cor;
33047
+ try {
33048
+ eng = JSON.parse(readFileSync2(engPath, "utf8"));
33049
+ cor = JSON.parse(readFileSync2(corePath, "utf8"));
33050
+ } catch {
33051
+ return [];
33052
+ }
33053
+ const engPaths = eng.paths ?? (eng.paths = {});
33054
+ const corPaths = cor.paths ?? {};
33055
+ const added = [];
33056
+ for (const [key, value] of Object.entries(corPaths)) {
33057
+ if (!(key in engPaths)) {
33058
+ engPaths[key] = value;
33059
+ added.push(`paths.${key}`);
33060
+ }
33061
+ }
33062
+ if (added.length)
33063
+ writeFileSync2(engPath, `${JSON.stringify(eng, null, 2)}
33064
+ `);
33065
+ return added;
33066
+ }
33067
+ function updateEngine(rootOrEngine, moduleUrl, { yes = false } = {}) {
33068
+ const engine = resolveEngine(rootOrEngine);
33069
+ if (!isEngine(engine)) {
33070
+ return {
33071
+ engine,
33072
+ action: "preview",
33073
+ valid: false,
33074
+ code: "NOT_AN_ENGINE",
33075
+ errors: [`${engine} is not a Content Engine. Run engine init first, or pass --engine <path>.`]
33076
+ };
33077
+ }
33078
+ const core = ensureCoreCheckout({ update: true });
33079
+ const refresh = [];
33080
+ const add = [];
33081
+ for (const rel of walkCoreFiles(core)) {
33082
+ const cls = classifyCoreFile(rel);
33083
+ if (cls === "refresh")
33084
+ refresh.push(rel);
33085
+ else if (cls === "add" && !existsSync3(join3(engine, rel)))
33086
+ add.push(rel);
33087
+ }
33088
+ if (!yes) {
33089
+ return {
33090
+ engine,
33091
+ action: "preview",
33092
+ source: contentEngineRepoUrl(),
33093
+ willRefresh: refresh,
33094
+ willAdd: add,
33095
+ next: "Re-run with --yes to apply. Vault data (profiles, needs, runs, media files) is never touched."
33096
+ };
33097
+ }
33098
+ const copy = (list) => {
33099
+ for (const rel of list) {
33100
+ const dest = join3(engine, rel);
33101
+ mkdirSync2(dirname3(dest), { recursive: true });
33102
+ copyFileSync(join3(core, rel), dest);
33103
+ }
33104
+ return list;
33105
+ };
33106
+ const refreshed = copy(refresh);
33107
+ const added = copy(add);
33108
+ const enginePaths = mergeEngineJson(engine, core);
33109
+ const workbenchBuild = buildWorkbench(engine);
33110
+ return {
33111
+ ...validateEngine(engine, moduleUrl),
33112
+ engine,
33113
+ action: "applied",
33114
+ source: contentEngineRepoUrl(),
33115
+ refreshed,
33116
+ added,
33117
+ enginePaths,
33118
+ workbenchBuild
33119
+ };
33120
+ }
33005
33121
  function detectEngines() {
33006
33122
  const extra = (process.env.EASYSOCIABLE_ENGINE_SEARCH_ROOTS || "").split(process.platform === "win32" ? ";" : ":").map((item) => item.trim()).filter(Boolean);
33007
33123
  const home = homedir2();
@@ -33310,6 +33426,15 @@ function buildV1Cli() {
33310
33426
  if (!built.ok)
33311
33427
  throw new Error(built.message);
33312
33428
  });
33429
+ jsonOption(engine.command("update").description("Sync core rules from the template (CLAUDE.md, workbench, platforms, templates) and add new scaffolds; never touches your vault data. Preview first; apply with --yes.").option("--engine <path>", "Content Engine path or parent", defaultEngineRoot()).option("--yes", "Apply the update (default is a dry-run preview)")).action((...args) => {
33430
+ const command = args.at(-1);
33431
+ const opts = command.opts();
33432
+ const result = updateEngine(String(opts.engine), CLI_MODULE_URL, { yes: opts.yes === true });
33433
+ print(result, commandWantsJson(command));
33434
+ const code = result.code;
33435
+ if (code)
33436
+ throw new Error(result.errors?.[0] ?? code);
33437
+ });
33313
33438
  const auth = program.command("auth").description("Manage the shared EasySociable credential");
33314
33439
  jsonOption(auth.command("status").description("Show authentication status")).action(async (...args) => {
33315
33440
  const command = args.at(-1);