@dforge-core/dforge-cli 0.2.16 → 0.2.18

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/dist/cli.js CHANGED
@@ -272,7 +272,7 @@ function fD({ input: e2 = import_node_process.stdin, output: u2 = import_node_pr
272
272
  e2.off("keypress", i), F2 && u2.write(import_sisteransi.cursor.show), e2.isTTY && !AD && e2.setRawMode(false), s.terminal = false, s.close();
273
273
  };
274
274
  }
275
- var import_sisteransi, import_node_process, g, import_node_readline, import_node_stream, import_picocolors, uD, W, tD, eD, FD, sD, w, N, I, R, r, iD, CD, ED, d, oD, y, V, nD, G, _, z, K, aD, k, hD, lD, xD, B, AD, S, gD, vD, h, x, dD, A, kD, $D, H, SD, OD, PD, J, LD, RD;
275
+ var import_sisteransi, import_node_process, g, import_node_readline, import_node_stream, import_picocolors, uD, W, tD, eD, FD, sD, w, N, I, R, r, iD, CD, ED, d, oD, y, V, nD, G, _, z, K, aD, k, hD, lD, xD, B, AD, S, gD, vD, h, x, dD, A, OD, PD, J, LD, RD;
276
276
  var init_dist = __esm({
277
277
  "node_modules/.pnpm/@clack+core@0.5.0/node_modules/@clack/core/dist/index.mjs"() {
278
278
  "use strict";
@@ -514,41 +514,6 @@ var init_dist = __esm({
514
514
  }
515
515
  };
516
516
  A = /* @__PURE__ */ new WeakMap();
517
- kD = Object.defineProperty;
518
- $D = (e2, u2, t) => u2 in e2 ? kD(e2, u2, { enumerable: true, configurable: true, writable: true, value: t }) : e2[u2] = t;
519
- H = (e2, u2, t) => ($D(e2, typeof u2 != "symbol" ? u2 + "" : u2, t), t);
520
- SD = class extends x {
521
- constructor(u2) {
522
- super(u2, false), H(this, "options"), H(this, "cursor", 0), this.options = u2.options, this.value = [...u2.initialValues ?? []], this.cursor = Math.max(this.options.findIndex(({ value: t }) => t === u2.cursorAt), 0), this.on("key", (t) => {
523
- t === "a" && this.toggleAll();
524
- }), this.on("cursor", (t) => {
525
- switch (t) {
526
- case "left":
527
- case "up":
528
- this.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1;
529
- break;
530
- case "down":
531
- case "right":
532
- this.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1;
533
- break;
534
- case "space":
535
- this.toggleValue();
536
- break;
537
- }
538
- });
539
- }
540
- get _value() {
541
- return this.options[this.cursor].value;
542
- }
543
- toggleAll() {
544
- const u2 = this.value.length === this.options.length;
545
- this.value = u2 ? [] : this.options.map((t) => t.value);
546
- }
547
- toggleValue() {
548
- const u2 = this.value.includes(this._value);
549
- this.value = u2 ? this.value.filter((t) => t !== this._value) : [...this.value, this._value];
550
- }
551
- };
552
517
  OD = Object.defineProperty;
553
518
  PD = (e2, u2, t) => u2 in e2 ? OD(e2, u2, { enumerable: true, configurable: true, writable: true, value: t }) : e2[u2] = t;
554
519
  J = (e2, u2, t) => (PD(e2, typeof u2 != "symbol" ? u2 + "" : u2, t), t);
@@ -598,7 +563,7 @@ var init_dist = __esm({
598
563
  function ce() {
599
564
  return import_node_process2.default.platform !== "win32" ? import_node_process2.default.env.TERM !== "linux" : !!import_node_process2.default.env.CI || !!import_node_process2.default.env.WT_SESSION || !!import_node_process2.default.env.TERMINUS_SUBLIME || import_node_process2.default.env.ConEmuTask === "{cmd::Cmder}" || import_node_process2.default.env.TERM_PROGRAM === "Terminus-Sublime" || import_node_process2.default.env.TERM_PROGRAM === "vscode" || import_node_process2.default.env.TERM === "xterm-256color" || import_node_process2.default.env.TERM === "alacritty" || import_node_process2.default.env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
600
565
  }
601
- var import_node_util, import_node_process2, import_picocolors2, import_sisteransi2, V2, u, le, L2, W2, C, ue, o, d2, k2, P2, A2, T, F, $e, _2, me, de, pe, q, D, U, K2, b2, G2, he, ye, ve, fe, xe, Ie, Se, J2, Y2, Ce;
566
+ var import_node_util, import_node_process2, import_picocolors2, import_sisteransi2, V2, u, le, L2, W2, C, ue, o, d2, k2, P2, A2, T, F, $e, _2, me, de, pe, q, D, U, K2, b2, G2, he, ye, ve, xe, Ie, Se, J2, Y2, Ce;
602
567
  var init_dist2 = __esm({
603
568
  "node_modules/.pnpm/@clack+prompts@0.11.0/node_modules/@clack/prompts/dist/index.mjs"() {
604
569
  "use strict";
@@ -722,46 +687,6 @@ ${import_picocolors2.default.gray(o)}`;
722
687
  return `${r2}${import_picocolors2.default.cyan(o)} ${G2({ cursor: this.cursor, options: this.options, maxItems: t.maxItems, style: (i, s) => n(i, s ? "active" : "inactive") }).join(`
723
688
  ${import_picocolors2.default.cyan(o)} `)}
724
689
  ${import_picocolors2.default.cyan(d2)}
725
- `;
726
- }
727
- } }).prompt();
728
- };
729
- fe = (t) => {
730
- const n = (r2, i) => {
731
- const s = r2.label ?? String(r2.value);
732
- return i === "active" ? `${import_picocolors2.default.cyan(A2)} ${s} ${r2.hint ? import_picocolors2.default.dim(`(${r2.hint})`) : ""}` : i === "selected" ? `${import_picocolors2.default.green(T)} ${import_picocolors2.default.dim(s)} ${r2.hint ? import_picocolors2.default.dim(`(${r2.hint})`) : ""}` : i === "cancelled" ? `${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(s))}` : i === "active-selected" ? `${import_picocolors2.default.green(T)} ${s} ${r2.hint ? import_picocolors2.default.dim(`(${r2.hint})`) : ""}` : i === "submitted" ? `${import_picocolors2.default.dim(s)}` : `${import_picocolors2.default.dim(F)} ${import_picocolors2.default.dim(s)}`;
733
- };
734
- return new SD({ options: t.options, initialValues: t.initialValues, required: t.required ?? true, cursorAt: t.cursorAt, validate(r2) {
735
- if (this.required && r2.length === 0) return `Please select at least one option.
736
- ${import_picocolors2.default.reset(import_picocolors2.default.dim(`Press ${import_picocolors2.default.gray(import_picocolors2.default.bgWhite(import_picocolors2.default.inverse(" space ")))} to select, ${import_picocolors2.default.gray(import_picocolors2.default.bgWhite(import_picocolors2.default.inverse(" enter ")))} to submit`))}`;
737
- }, render() {
738
- const r2 = `${import_picocolors2.default.gray(o)}
739
- ${b2(this.state)} ${t.message}
740
- `, i = (s, c) => {
741
- const a = this.value.includes(s.value);
742
- return c && a ? n(s, "active-selected") : a ? n(s, "selected") : n(s, c ? "active" : "inactive");
743
- };
744
- switch (this.state) {
745
- case "submit":
746
- return `${r2}${import_picocolors2.default.gray(o)} ${this.options.filter(({ value: s }) => this.value.includes(s)).map((s) => n(s, "submitted")).join(import_picocolors2.default.dim(", ")) || import_picocolors2.default.dim("none")}`;
747
- case "cancel": {
748
- const s = this.options.filter(({ value: c }) => this.value.includes(c)).map((c) => n(c, "cancelled")).join(import_picocolors2.default.dim(", "));
749
- return `${r2}${import_picocolors2.default.gray(o)} ${s.trim() ? `${s}
750
- ${import_picocolors2.default.gray(o)}` : ""}`;
751
- }
752
- case "error": {
753
- const s = this.error.split(`
754
- `).map((c, a) => a === 0 ? `${import_picocolors2.default.yellow(d2)} ${import_picocolors2.default.yellow(c)}` : ` ${c}`).join(`
755
- `);
756
- return `${r2 + import_picocolors2.default.yellow(o)} ${G2({ options: this.options, cursor: this.cursor, maxItems: t.maxItems, style: i }).join(`
757
- ${import_picocolors2.default.yellow(o)} `)}
758
- ${s}
759
- `;
760
- }
761
- default:
762
- return `${r2}${import_picocolors2.default.cyan(o)} ${G2({ options: this.options, cursor: this.cursor, maxItems: t.maxItems, style: i }).join(`
763
- ${import_picocolors2.default.cyan(o)} `)}
764
- ${import_picocolors2.default.cyan(d2)}
765
690
  `;
766
691
  }
767
692
  } }).prompt();
@@ -802,7 +727,7 @@ ${import_picocolors2.default.gray(d2)} ${t}
802
727
  }, R2 = (m2) => m2.replace(/\.+$/, ""), O2 = (m2) => {
803
728
  const h2 = (performance.now() - m2) / 1e3, w2 = Math.floor(h2 / 60), I2 = Math.floor(h2 % 60);
804
729
  return w2 > 0 ? `[${w2}m ${I2}s]` : `[${I2}s]`;
805
- }, H2 = (m2 = "") => {
730
+ }, H = (m2 = "") => {
806
731
  a = true, s = fD(), l2 = R2(m2), g2 = performance.now(), process.stdout.write(`${import_picocolors2.default.gray(o)}
807
732
  `);
808
733
  let h2 = 0, w2 = 0;
@@ -825,7 +750,7 @@ ${import_picocolors2.default.gray(d2)} ${t}
825
750
  `) : process.stdout.write(`${w2} ${l2}
826
751
  `), E(), s();
827
752
  };
828
- return { start: H2, stop: N2, message: (m2 = "") => {
753
+ return { start: H, stop: N2, message: (m2 = "") => {
829
754
  l2 = R2(m2 ?? l2);
830
755
  } };
831
756
  };
@@ -902,19 +827,46 @@ function buildManifest(opts, moduleId) {
902
827
  if (opts.license) manifest.license = opts.license;
903
828
  if (opts.dependencies.length > 0) {
904
829
  manifest.dependencies = Object.fromEntries(
905
- opts.dependencies.map((d3) => [d3, ">=0.0.1"])
830
+ opts.dependencies.map(
831
+ (d3) => typeof d3 === "string" ? [d3, DEPENDENCY_RANGE] : [d3.module, { version: DEPENDENCY_RANGE, entities: d3.entities }]
832
+ )
906
833
  );
907
834
  }
908
835
  return manifest;
909
836
  }
837
+ function buildDepsContract(dep, consumerCode) {
838
+ return {
839
+ module: dep.module,
840
+ version: DEPENDENCY_RANGE,
841
+ entities: Object.fromEntries(
842
+ dep.entities.map((e2) => [
843
+ e2,
844
+ { pk: `${e2}_id`, use: [`ref:${consumerCode}`] }
845
+ ])
846
+ )
847
+ };
848
+ }
910
849
  function buildEntity(entity) {
911
850
  const traits = entity.traits === "identity+audit" ? ["identity", "audit"] : ["identity"];
912
851
  const built = {
913
852
  description: entity.label,
914
853
  dbObject: entity.name,
915
- toString: "{id}",
854
+ // The traits only add a PK and audit stamps, so an entity with no fields
855
+ // of its own has nothing renderable: its grid view fails the data-view
856
+ // column check and `toString` has nothing to interpolate. Scaffold one
857
+ // visible name column so the module validates and the grid shows a row.
858
+ toString: `{${NAME_FIELD}}`,
916
859
  traits,
917
- fields: {}
860
+ fields: {
861
+ [NAME_FIELD]: {
862
+ dbDatatype: "varchar",
863
+ fieldTypeCd: "text",
864
+ flags: "VEM",
865
+ maxLen: 200,
866
+ orderNum: 10,
867
+ description: "Name"
868
+ }
869
+ }
918
870
  };
919
871
  if (entity.constraints?.length) {
920
872
  built.constraints = Object.fromEntries(
@@ -999,7 +951,8 @@ function buildTranslations(opts) {
999
951
  for (const e2 of opts.entities) {
1000
952
  const fields = {
1001
953
  // identity trait → primary key column
1002
- [`${e2.name}_id`]: { label: `${e2.label} ID` }
954
+ [`${e2.name}_id`]: { label: `${e2.label} ID` },
955
+ [NAME_FIELD]: { label: "Name" }
1003
956
  };
1004
957
  if (e2.traits === "identity+audit") {
1005
958
  fields.created_date = { label: "Created Date" };
@@ -1040,8 +993,9 @@ function buildTranslations(opts) {
1040
993
  }
1041
994
  };
1042
995
  }
1043
- function buildSeedData() {
1044
- return [];
996
+ function buildSeedData(entity) {
997
+ const entityCode = typeof entity === "string" ? entity : entity?.name ?? "";
998
+ return { entityCode, records: [] };
1045
999
  }
1046
1000
  function buildGitignore() {
1047
1001
  return [
@@ -1055,30 +1009,78 @@ function buildGitignore() {
1055
1009
  ""
1056
1010
  ].join("\n");
1057
1011
  }
1012
+ function schemaEntries() {
1013
+ return SCHEMA_BINDINGS.map((b3) => ({
1014
+ fileMatch: b3.fileMatch,
1015
+ url: `${SCHEMA_BASE}/${b3.schema}.schema.json`
1016
+ }));
1017
+ }
1058
1018
  function buildVscodeSettings() {
1059
- return {
1060
- "json.schemas": SCHEMA_BINDINGS.map((b3) => ({
1061
- fileMatch: b3.fileMatch,
1062
- url: `${SCHEMA_BASE}/${b3.schema}.schema.json`
1063
- }))
1064
- };
1019
+ return { "json.schemas": schemaEntries() };
1065
1020
  }
1066
1021
  function buildZedSettings() {
1067
1022
  return {
1068
- languages: {
1069
- JSON: {
1070
- "json.schemas": SCHEMA_BINDINGS.map((b3) => ({
1071
- fileMatch: b3.fileMatch,
1072
- url: `${SCHEMA_BASE}/${b3.schema}.schema.json`
1073
- }))
1023
+ lsp: {
1024
+ "json-language-server": {
1025
+ settings: { json: { schemas: schemaEntries() } }
1026
+ }
1027
+ },
1028
+ context_servers: {
1029
+ dforge: {
1030
+ source: "custom",
1031
+ command: "npx",
1032
+ args: ["-y", "@dforge-core/dforge-mcp@latest"],
1033
+ env: {}
1074
1034
  }
1075
1035
  }
1076
1036
  };
1077
1037
  }
1078
- var SCHEMA_BASE, SCHEMA_BINDINGS;
1038
+ function buildZedTasks() {
1039
+ const CLI = "npx";
1040
+ const CLI_ARGS = ["-y", "@dforge-core/dforge-cli@latest"];
1041
+ const DEFAULT_TENANT = "http://localhost:5179";
1042
+ const task = (label, args) => ({
1043
+ label: `dForge: ${label}`,
1044
+ command: CLI,
1045
+ args: [...CLI_ARGS, ...args],
1046
+ cwd: "$ZED_WORKTREE_ROOT",
1047
+ env: { DFORGE_URL: DEFAULT_TENANT },
1048
+ use_new_terminal: false,
1049
+ allow_concurrent_runs: false,
1050
+ reveal: "always"
1051
+ });
1052
+ return [
1053
+ task("Pack module", ["module", "pack", "$ZED_WORKTREE_ROOT"]),
1054
+ // --force matches the extension's dev-loop default: without it the CLI
1055
+ // skips the reinstall when the version hasn't changed and your edits
1056
+ // silently never reach the tenant.
1057
+ task("Install module to tenant", [
1058
+ "module",
1059
+ "install",
1060
+ "--path",
1061
+ "$ZED_WORKTREE_ROOT",
1062
+ "--url",
1063
+ "$DFORGE_URL",
1064
+ "--force"
1065
+ ]),
1066
+ task("Sign in to tenant", [
1067
+ "auth",
1068
+ "login",
1069
+ "--url",
1070
+ "$DFORGE_URL",
1071
+ "--login-url",
1072
+ "$DFORGE_URL"
1073
+ ]),
1074
+ task("Show signed-in user", ["auth", "whoami", "--url", "$DFORGE_URL"]),
1075
+ task("List installed modules", ["module", "list", "--url", "$DFORGE_URL"])
1076
+ ];
1077
+ }
1078
+ var DEPENDENCY_RANGE, NAME_FIELD, SCHEMA_BASE, SCHEMA_BINDINGS;
1079
1079
  var init_templates = __esm({
1080
1080
  "src/init/templates.ts"() {
1081
1081
  "use strict";
1082
+ DEPENDENCY_RANGE = ">=0.0.1";
1083
+ NAME_FIELD = "name";
1082
1084
  SCHEMA_BASE = "https://cdn.jsdelivr.net/npm/@dforge-core/dforge-mcp@latest/resources/schemas";
1083
1085
  SCHEMA_BINDINGS = [
1084
1086
  { fileMatch: ["manifest.json"], schema: "manifest" },
@@ -1087,8 +1089,12 @@ var init_templates = __esm({
1087
1089
  { fileMatch: ["ui/folders.json"], schema: "folders" },
1088
1090
  { fileMatch: ["ui/menus.json"], schema: "menus" },
1089
1091
  { fileMatch: ["ui/reports.json"], schema: "reports" },
1092
+ { fileMatch: ["ui/print_templates.json"], schema: "print-templates" },
1090
1093
  { fileMatch: ["security/roles.json"], schema: "roles" },
1091
1094
  { fileMatch: ["logic/jobs.json"], schema: "jobs" },
1095
+ { fileMatch: ["logic/triggers.json"], schema: "triggers" },
1096
+ { fileMatch: ["logic/webhooks.json"], schema: "webhooks" },
1097
+ { fileMatch: ["deps/*.json"], schema: "deps" },
1092
1098
  { fileMatch: ["seed-data/*.json"], schema: "seed-data" },
1093
1099
  { fileMatch: ["settings.json"], schema: "settings" }
1094
1100
  ];
@@ -1156,6 +1162,12 @@ async function runInitModule(argv2) {
1156
1162
  Se(`Created module ${opts.code} at ${opts.path}`);
1157
1163
  }
1158
1164
  console.log("");
1165
+ if (opts.dependencies.length > 0) {
1166
+ const files = opts.dependencies.map((d3) => `deps/${typeof d3 === "string" ? d3 : d3.module}.json`).join(", ");
1167
+ console.log(`Wrote ${files}. Correct each entity's 'pk' against the provider and`);
1168
+ console.log("replace the placeholder 'use' token with the real usage before you pack.");
1169
+ console.log("");
1170
+ }
1159
1171
  console.log("Next steps:");
1160
1172
  console.log(` cd ${path2.relative(process.cwd(), opts.path) || "."}`);
1161
1173
  console.log(` dforge-cli module install --path . --code <tenant>`);
@@ -1266,11 +1278,33 @@ function buildOptsFromArgs(absPath, args) {
1266
1278
  license: args.license ?? "MIT",
1267
1279
  version,
1268
1280
  dbSchemaVersion,
1269
- dependencies: args.dependencies ?? ["admin", "metadata"],
1281
+ dependencies: parseDependencies(args.dependencies ?? []),
1270
1282
  preset,
1271
1283
  entities
1272
1284
  };
1273
1285
  }
1286
+ function parseDependencies(tokens) {
1287
+ return tokens.map((token) => {
1288
+ const [module2, entityList] = token.split(":");
1289
+ if (!module2 || !entityList) {
1290
+ throw new Error(
1291
+ `dforge-cli init module: --dependencies "${token}" must name the entities you consume, as module:entity[+entity]. Every dependency needs a deps/${module2 || "<module>"}.json contract declaring at least one entity, so a dependency with no named entity cannot be scaffolded. If you do not consume anything from it yet, leave it out and add it later with dforge_dependency_add.`
1292
+ );
1293
+ }
1294
+ if (SYSTEM_MODULES.has(module2)) {
1295
+ throw new Error(
1296
+ `dforge-cli init module: '${module2}' is a system module \u2014 it is provisioned into every tenant, so depending on it buys nothing. Declare it by hand only to require a minimum platform version for a feature you use (e.g. "metadata": ">=1.5.0"), with a contract naming the entity that feature introduced.`
1297
+ );
1298
+ }
1299
+ const entities = entityList.split("+").map((e2) => e2.trim()).filter(Boolean);
1300
+ if (entities.length === 0) {
1301
+ throw new Error(
1302
+ `dforge-cli init module: --dependencies "${token}" names no entities after the colon.`
1303
+ );
1304
+ }
1305
+ return { module: module2, entities };
1306
+ });
1307
+ }
1274
1308
  function printModuleHelp() {
1275
1309
  console.log("Usage: dforge-cli init module <path> [options]");
1276
1310
  console.log("");
@@ -1285,7 +1319,8 @@ function printModuleHelp() {
1285
1319
  console.log(" --license <id> Default: MIT");
1286
1320
  console.log(" --version <semver> Default: 0.1.0");
1287
1321
  console.log(" --db-schema-version <ver> Default: 0.0.1");
1288
- console.log(" --dependencies <a,b> Default: admin,metadata");
1322
+ console.log(" --dependencies <mod:ent> Consumed module + entities, e.g. fin:invoice+line.");
1323
+ console.log(" Repeatable/comma-separated. Default: none.");
1289
1324
  console.log(" --preset <p> minimal | minimal-plus | full (default: minimal)");
1290
1325
  console.log(" --entity <name[,name\u2026]> Entities to scaffold (default: item). Repeatable.");
1291
1326
  console.log(" --traits <t> identity+audit | identity (default: identity+audit)");
@@ -1328,15 +1363,6 @@ async function collectOpts(absPath) {
1328
1363
  initialValue: "0.0.1",
1329
1364
  validate: validateSemver
1330
1365
  }),
1331
- dependencies: () => fe({
1332
- message: "Depend on system modules (space to toggle)",
1333
- options: [
1334
- { value: "admin", label: "admin (required for most modules)" },
1335
- { value: "metadata", label: "metadata (required for most modules)" }
1336
- ],
1337
- initialValues: ["admin", "metadata"],
1338
- required: false
1339
- }),
1340
1366
  preset: () => ve({
1341
1367
  message: "Scaffold preset",
1342
1368
  options: [
@@ -1386,7 +1412,7 @@ async function collectOpts(absPath) {
1386
1412
  license: meta.license ?? "MIT",
1387
1413
  version: meta.version,
1388
1414
  dbSchemaVersion: meta.dbSchemaVersion,
1389
- dependencies: meta.dependencies ?? [],
1415
+ dependencies: [],
1390
1416
  preset: meta.preset,
1391
1417
  entities
1392
1418
  };
@@ -1442,16 +1468,24 @@ function writeAll(opts) {
1442
1468
  writeJson(path2.join(root, "ui", "menus.json"), buildMenus(opts));
1443
1469
  writeJson(path2.join(root, "ui", "actions.json"), buildActions());
1444
1470
  writeJson(path2.join(root, "security", "roles.json"), buildRoles(opts));
1471
+ for (const dep of opts.dependencies) {
1472
+ if (typeof dep === "string") continue;
1473
+ writeJson(
1474
+ path2.join(root, "deps", `${dep.module}.json`),
1475
+ buildDepsContract(dep, opts.code)
1476
+ );
1477
+ }
1445
1478
  writeText(path2.join(root, ".gitignore"), buildGitignore());
1446
1479
  writeJson(path2.join(root, ".vscode", "settings.json"), buildVscodeSettings());
1447
1480
  writeJson(path2.join(root, ".zed", "settings.json"), buildZedSettings());
1481
+ writeJson(path2.join(root, ".zed", "tasks.json"), buildZedTasks());
1448
1482
  if (opts.preset === "full") {
1449
1483
  writeJson(path2.join(root, "settings.json"), buildSettings());
1450
1484
  writeJson(path2.join(root, "translations", "en-US.json"), buildTranslations(opts));
1451
1485
  for (const e2 of opts.entities) {
1452
1486
  writeJson(
1453
1487
  path2.join(root, "seed-data", `01-${e2.name}.json`),
1454
- buildSeedData()
1488
+ buildSeedData(e2)
1455
1489
  );
1456
1490
  }
1457
1491
  ensureDir(path2.join(root, "logic", "actions"));
@@ -1480,7 +1514,7 @@ function tryGitUserName() {
1480
1514
  return void 0;
1481
1515
  }
1482
1516
  }
1483
- var fs2, path2, import_node_child_process2, import_node_crypto, CANCEL_EXIT, PRESETS, TRAITS_VALUES;
1517
+ var fs2, path2, import_node_child_process2, import_node_crypto, CANCEL_EXIT, PRESETS, TRAITS_VALUES, SYSTEM_MODULES;
1484
1518
  var init_module = __esm({
1485
1519
  "src/init/module.ts"() {
1486
1520
  "use strict";
@@ -1494,6 +1528,7 @@ var init_module = __esm({
1494
1528
  CANCEL_EXIT = 130;
1495
1529
  PRESETS = /* @__PURE__ */ new Set(["minimal", "minimal-plus", "full"]);
1496
1530
  TRAITS_VALUES = /* @__PURE__ */ new Set(["identity+audit", "identity"]);
1531
+ SYSTEM_MODULES = /* @__PURE__ */ new Set(["admin", "metadata", "workspace"]);
1497
1532
  }
1498
1533
  });
1499
1534
 
package/dist/lib.d.mts CHANGED
@@ -13,6 +13,16 @@ interface EntitySpec {
13
13
  traits: Traits;
14
14
  constraints?: ConstraintSpec[];
15
15
  }
16
+ /**
17
+ * One declared dependency. `entities` is what the module consumes from it and
18
+ * is never empty: the platform requires a deps/<module>.json contract naming at
19
+ * least one entity for every manifest dependency, so a dependency we cannot
20
+ * name an entity for is one we must not scaffold.
21
+ */
22
+ interface DependencySpec {
23
+ module: string;
24
+ entities: string[];
25
+ }
16
26
  interface ScaffoldOpts {
17
27
  path: string;
18
28
  code: string;
@@ -22,7 +32,11 @@ interface ScaffoldOpts {
22
32
  license: string;
23
33
  version: string;
24
34
  dbSchemaVersion: string;
25
- dependencies: string[];
35
+ /**
36
+ * Accepts bare module codes too: @dforge-core/dforge-mcp calls these builders
37
+ * across a caret range and older published versions still pass string[].
38
+ */
39
+ dependencies: Array<DependencySpec | string>;
26
40
  preset: Preset;
27
41
  entities: EntitySpec[];
28
42
  }
@@ -38,7 +52,15 @@ interface Manifest {
38
52
  name: string;
39
53
  };
40
54
  license?: string;
41
- dependencies?: Record<string, string>;
55
+ /**
56
+ * Either a bare semver range or the object form that narrows the dependency
57
+ * to named entities. The scaffolder always writes the object form, since it
58
+ * only declares a dependency whose consumed entities it knows.
59
+ */
60
+ dependencies?: Record<string, string | {
61
+ version: string;
62
+ entities: string[];
63
+ }>;
42
64
  entities: Record<string, string>;
43
65
  created?: string;
44
66
  updated?: string;
@@ -61,6 +83,22 @@ interface DataView {
61
83
  }
62
84
 
63
85
  declare function buildManifest(opts: ScaffoldOpts, moduleId: string): Manifest;
86
+ /** Range written for a scaffolded dependency, in the manifest and its contract alike. */
87
+ declare const DEPENDENCY_RANGE = ">=0.0.1";
88
+ /**
89
+ * The deps/<module>.json contract that every manifest dependency requires —
90
+ * without it the module fails `module validate`, `module pack` and install.
91
+ * `pk` follows the identity trait's `<entity>_id`, and `use` is a placeholder
92
+ * naming this module: both are starting points the author has to correct, which
93
+ * is what the post-scaffold note says.
94
+ */
95
+ declare function buildDepsContract(dep: DependencySpec, consumerCode: string): Record<string, unknown>;
96
+ /**
97
+ * The one field every scaffolded entity gets: a visible, editable, mandatory
98
+ * label column. It is what `toString` interpolates and what the entity's grid
99
+ * renders.
100
+ */
101
+ declare const NAME_FIELD = "name";
64
102
  declare function buildEntity(entity: EntitySpec): Entity;
65
103
  declare function buildDataViews(entities: EntitySpec[]): Record<string, DataView>;
66
104
  declare function buildFolders(opts: ScaffoldOpts): Record<string, unknown>;
@@ -69,9 +107,15 @@ declare function buildRoles(opts: ScaffoldOpts): Record<string, unknown>;
69
107
  declare function buildActions(): Record<string, unknown>;
70
108
  declare function buildSettings(): Record<string, unknown>;
71
109
  declare function buildTranslations(opts: ScaffoldOpts): Record<string, unknown>;
72
- declare function buildSeedData(): unknown[];
110
+ /**
111
+ * A seed file is an OBJECT ({ entityCode, records }), not a bare array — a bare
112
+ * array fails to deserialize and takes `module validate` down with it. Ships
113
+ * with no records: seeding needs explicit PKs, which only the author can pick.
114
+ */
115
+ declare function buildSeedData(entity?: EntitySpec | string): Record<string, unknown>;
73
116
  declare function buildGitignore(): string;
74
117
  declare function buildVscodeSettings(): Record<string, unknown>;
75
118
  declare function buildZedSettings(): Record<string, unknown>;
119
+ declare function buildZedTasks(): unknown[];
76
120
 
77
- export { type ConstraintSpec, type DataView, type Entity, type EntitySpec, type Manifest, type Preset, type ScaffoldOpts, type Traits, buildActions, buildDataViews, buildEntity, buildFolders, buildGitignore, buildManifest, buildMenus, buildRoles, buildSeedData, buildSettings, buildTranslations, buildVscodeSettings, buildZedSettings };
121
+ export { type ConstraintSpec, DEPENDENCY_RANGE, type DataView, type DependencySpec, type Entity, type EntitySpec, type Manifest, NAME_FIELD, type Preset, type ScaffoldOpts, type Traits, buildActions, buildDataViews, buildDepsContract, buildEntity, buildFolders, buildGitignore, buildManifest, buildMenus, buildRoles, buildSeedData, buildSettings, buildTranslations, buildVscodeSettings, buildZedSettings, buildZedTasks };
package/dist/lib.d.ts CHANGED
@@ -13,6 +13,16 @@ interface EntitySpec {
13
13
  traits: Traits;
14
14
  constraints?: ConstraintSpec[];
15
15
  }
16
+ /**
17
+ * One declared dependency. `entities` is what the module consumes from it and
18
+ * is never empty: the platform requires a deps/<module>.json contract naming at
19
+ * least one entity for every manifest dependency, so a dependency we cannot
20
+ * name an entity for is one we must not scaffold.
21
+ */
22
+ interface DependencySpec {
23
+ module: string;
24
+ entities: string[];
25
+ }
16
26
  interface ScaffoldOpts {
17
27
  path: string;
18
28
  code: string;
@@ -22,7 +32,11 @@ interface ScaffoldOpts {
22
32
  license: string;
23
33
  version: string;
24
34
  dbSchemaVersion: string;
25
- dependencies: string[];
35
+ /**
36
+ * Accepts bare module codes too: @dforge-core/dforge-mcp calls these builders
37
+ * across a caret range and older published versions still pass string[].
38
+ */
39
+ dependencies: Array<DependencySpec | string>;
26
40
  preset: Preset;
27
41
  entities: EntitySpec[];
28
42
  }
@@ -38,7 +52,15 @@ interface Manifest {
38
52
  name: string;
39
53
  };
40
54
  license?: string;
41
- dependencies?: Record<string, string>;
55
+ /**
56
+ * Either a bare semver range or the object form that narrows the dependency
57
+ * to named entities. The scaffolder always writes the object form, since it
58
+ * only declares a dependency whose consumed entities it knows.
59
+ */
60
+ dependencies?: Record<string, string | {
61
+ version: string;
62
+ entities: string[];
63
+ }>;
42
64
  entities: Record<string, string>;
43
65
  created?: string;
44
66
  updated?: string;
@@ -61,6 +83,22 @@ interface DataView {
61
83
  }
62
84
 
63
85
  declare function buildManifest(opts: ScaffoldOpts, moduleId: string): Manifest;
86
+ /** Range written for a scaffolded dependency, in the manifest and its contract alike. */
87
+ declare const DEPENDENCY_RANGE = ">=0.0.1";
88
+ /**
89
+ * The deps/<module>.json contract that every manifest dependency requires —
90
+ * without it the module fails `module validate`, `module pack` and install.
91
+ * `pk` follows the identity trait's `<entity>_id`, and `use` is a placeholder
92
+ * naming this module: both are starting points the author has to correct, which
93
+ * is what the post-scaffold note says.
94
+ */
95
+ declare function buildDepsContract(dep: DependencySpec, consumerCode: string): Record<string, unknown>;
96
+ /**
97
+ * The one field every scaffolded entity gets: a visible, editable, mandatory
98
+ * label column. It is what `toString` interpolates and what the entity's grid
99
+ * renders.
100
+ */
101
+ declare const NAME_FIELD = "name";
64
102
  declare function buildEntity(entity: EntitySpec): Entity;
65
103
  declare function buildDataViews(entities: EntitySpec[]): Record<string, DataView>;
66
104
  declare function buildFolders(opts: ScaffoldOpts): Record<string, unknown>;
@@ -69,9 +107,15 @@ declare function buildRoles(opts: ScaffoldOpts): Record<string, unknown>;
69
107
  declare function buildActions(): Record<string, unknown>;
70
108
  declare function buildSettings(): Record<string, unknown>;
71
109
  declare function buildTranslations(opts: ScaffoldOpts): Record<string, unknown>;
72
- declare function buildSeedData(): unknown[];
110
+ /**
111
+ * A seed file is an OBJECT ({ entityCode, records }), not a bare array — a bare
112
+ * array fails to deserialize and takes `module validate` down with it. Ships
113
+ * with no records: seeding needs explicit PKs, which only the author can pick.
114
+ */
115
+ declare function buildSeedData(entity?: EntitySpec | string): Record<string, unknown>;
73
116
  declare function buildGitignore(): string;
74
117
  declare function buildVscodeSettings(): Record<string, unknown>;
75
118
  declare function buildZedSettings(): Record<string, unknown>;
119
+ declare function buildZedTasks(): unknown[];
76
120
 
77
- export { type ConstraintSpec, type DataView, type Entity, type EntitySpec, type Manifest, type Preset, type ScaffoldOpts, type Traits, buildActions, buildDataViews, buildEntity, buildFolders, buildGitignore, buildManifest, buildMenus, buildRoles, buildSeedData, buildSettings, buildTranslations, buildVscodeSettings, buildZedSettings };
121
+ export { type ConstraintSpec, DEPENDENCY_RANGE, type DataView, type DependencySpec, type Entity, type EntitySpec, type Manifest, NAME_FIELD, type Preset, type ScaffoldOpts, type Traits, buildActions, buildDataViews, buildDepsContract, buildEntity, buildFolders, buildGitignore, buildManifest, buildMenus, buildRoles, buildSeedData, buildSettings, buildTranslations, buildVscodeSettings, buildZedSettings, buildZedTasks };
package/dist/lib.js CHANGED
@@ -20,8 +20,11 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/lib.ts
21
21
  var lib_exports = {};
22
22
  __export(lib_exports, {
23
+ DEPENDENCY_RANGE: () => DEPENDENCY_RANGE,
24
+ NAME_FIELD: () => NAME_FIELD,
23
25
  buildActions: () => buildActions,
24
26
  buildDataViews: () => buildDataViews,
27
+ buildDepsContract: () => buildDepsContract,
25
28
  buildEntity: () => buildEntity,
26
29
  buildFolders: () => buildFolders,
27
30
  buildGitignore: () => buildGitignore,
@@ -32,7 +35,8 @@ __export(lib_exports, {
32
35
  buildSettings: () => buildSettings,
33
36
  buildTranslations: () => buildTranslations,
34
37
  buildVscodeSettings: () => buildVscodeSettings,
35
- buildZedSettings: () => buildZedSettings
38
+ buildZedSettings: () => buildZedSettings,
39
+ buildZedTasks: () => buildZedTasks
36
40
  });
37
41
  module.exports = __toCommonJS(lib_exports);
38
42
 
@@ -57,19 +61,48 @@ function buildManifest(opts, moduleId) {
57
61
  if (opts.license) manifest.license = opts.license;
58
62
  if (opts.dependencies.length > 0) {
59
63
  manifest.dependencies = Object.fromEntries(
60
- opts.dependencies.map((d) => [d, ">=0.0.1"])
64
+ opts.dependencies.map(
65
+ (d) => typeof d === "string" ? [d, DEPENDENCY_RANGE] : [d.module, { version: DEPENDENCY_RANGE, entities: d.entities }]
66
+ )
61
67
  );
62
68
  }
63
69
  return manifest;
64
70
  }
71
+ var DEPENDENCY_RANGE = ">=0.0.1";
72
+ function buildDepsContract(dep, consumerCode) {
73
+ return {
74
+ module: dep.module,
75
+ version: DEPENDENCY_RANGE,
76
+ entities: Object.fromEntries(
77
+ dep.entities.map((e) => [
78
+ e,
79
+ { pk: `${e}_id`, use: [`ref:${consumerCode}`] }
80
+ ])
81
+ )
82
+ };
83
+ }
84
+ var NAME_FIELD = "name";
65
85
  function buildEntity(entity) {
66
86
  const traits = entity.traits === "identity+audit" ? ["identity", "audit"] : ["identity"];
67
87
  const built = {
68
88
  description: entity.label,
69
89
  dbObject: entity.name,
70
- toString: "{id}",
90
+ // The traits only add a PK and audit stamps, so an entity with no fields
91
+ // of its own has nothing renderable: its grid view fails the data-view
92
+ // column check and `toString` has nothing to interpolate. Scaffold one
93
+ // visible name column so the module validates and the grid shows a row.
94
+ toString: `{${NAME_FIELD}}`,
71
95
  traits,
72
- fields: {}
96
+ fields: {
97
+ [NAME_FIELD]: {
98
+ dbDatatype: "varchar",
99
+ fieldTypeCd: "text",
100
+ flags: "VEM",
101
+ maxLen: 200,
102
+ orderNum: 10,
103
+ description: "Name"
104
+ }
105
+ }
73
106
  };
74
107
  if (entity.constraints?.length) {
75
108
  built.constraints = Object.fromEntries(
@@ -154,7 +187,8 @@ function buildTranslations(opts) {
154
187
  for (const e of opts.entities) {
155
188
  const fields = {
156
189
  // identity trait → primary key column
157
- [`${e.name}_id`]: { label: `${e.label} ID` }
190
+ [`${e.name}_id`]: { label: `${e.label} ID` },
191
+ [NAME_FIELD]: { label: "Name" }
158
192
  };
159
193
  if (e.traits === "identity+audit") {
160
194
  fields.created_date = { label: "Created Date" };
@@ -195,8 +229,9 @@ function buildTranslations(opts) {
195
229
  }
196
230
  };
197
231
  }
198
- function buildSeedData() {
199
- return [];
232
+ function buildSeedData(entity) {
233
+ const entityCode = typeof entity === "string" ? entity : entity?.name ?? "";
234
+ return { entityCode, records: [] };
200
235
  }
201
236
  function buildGitignore() {
202
237
  return [
@@ -218,35 +253,88 @@ var SCHEMA_BINDINGS = [
218
253
  { fileMatch: ["ui/folders.json"], schema: "folders" },
219
254
  { fileMatch: ["ui/menus.json"], schema: "menus" },
220
255
  { fileMatch: ["ui/reports.json"], schema: "reports" },
256
+ { fileMatch: ["ui/print_templates.json"], schema: "print-templates" },
221
257
  { fileMatch: ["security/roles.json"], schema: "roles" },
222
258
  { fileMatch: ["logic/jobs.json"], schema: "jobs" },
259
+ { fileMatch: ["logic/triggers.json"], schema: "triggers" },
260
+ { fileMatch: ["logic/webhooks.json"], schema: "webhooks" },
261
+ { fileMatch: ["deps/*.json"], schema: "deps" },
223
262
  { fileMatch: ["seed-data/*.json"], schema: "seed-data" },
224
263
  { fileMatch: ["settings.json"], schema: "settings" }
225
264
  ];
265
+ function schemaEntries() {
266
+ return SCHEMA_BINDINGS.map((b) => ({
267
+ fileMatch: b.fileMatch,
268
+ url: `${SCHEMA_BASE}/${b.schema}.schema.json`
269
+ }));
270
+ }
226
271
  function buildVscodeSettings() {
227
- return {
228
- "json.schemas": SCHEMA_BINDINGS.map((b) => ({
229
- fileMatch: b.fileMatch,
230
- url: `${SCHEMA_BASE}/${b.schema}.schema.json`
231
- }))
232
- };
272
+ return { "json.schemas": schemaEntries() };
233
273
  }
234
274
  function buildZedSettings() {
235
275
  return {
236
- languages: {
237
- JSON: {
238
- "json.schemas": SCHEMA_BINDINGS.map((b) => ({
239
- fileMatch: b.fileMatch,
240
- url: `${SCHEMA_BASE}/${b.schema}.schema.json`
241
- }))
276
+ lsp: {
277
+ "json-language-server": {
278
+ settings: { json: { schemas: schemaEntries() } }
279
+ }
280
+ },
281
+ context_servers: {
282
+ dforge: {
283
+ source: "custom",
284
+ command: "npx",
285
+ args: ["-y", "@dforge-core/dforge-mcp@latest"],
286
+ env: {}
242
287
  }
243
288
  }
244
289
  };
245
290
  }
291
+ function buildZedTasks() {
292
+ const CLI = "npx";
293
+ const CLI_ARGS = ["-y", "@dforge-core/dforge-cli@latest"];
294
+ const DEFAULT_TENANT = "http://localhost:5179";
295
+ const task = (label, args) => ({
296
+ label: `dForge: ${label}`,
297
+ command: CLI,
298
+ args: [...CLI_ARGS, ...args],
299
+ cwd: "$ZED_WORKTREE_ROOT",
300
+ env: { DFORGE_URL: DEFAULT_TENANT },
301
+ use_new_terminal: false,
302
+ allow_concurrent_runs: false,
303
+ reveal: "always"
304
+ });
305
+ return [
306
+ task("Pack module", ["module", "pack", "$ZED_WORKTREE_ROOT"]),
307
+ // --force matches the extension's dev-loop default: without it the CLI
308
+ // skips the reinstall when the version hasn't changed and your edits
309
+ // silently never reach the tenant.
310
+ task("Install module to tenant", [
311
+ "module",
312
+ "install",
313
+ "--path",
314
+ "$ZED_WORKTREE_ROOT",
315
+ "--url",
316
+ "$DFORGE_URL",
317
+ "--force"
318
+ ]),
319
+ task("Sign in to tenant", [
320
+ "auth",
321
+ "login",
322
+ "--url",
323
+ "$DFORGE_URL",
324
+ "--login-url",
325
+ "$DFORGE_URL"
326
+ ]),
327
+ task("Show signed-in user", ["auth", "whoami", "--url", "$DFORGE_URL"]),
328
+ task("List installed modules", ["module", "list", "--url", "$DFORGE_URL"])
329
+ ];
330
+ }
246
331
  // Annotate the CommonJS export names for ESM import in node:
247
332
  0 && (module.exports = {
333
+ DEPENDENCY_RANGE,
334
+ NAME_FIELD,
248
335
  buildActions,
249
336
  buildDataViews,
337
+ buildDepsContract,
250
338
  buildEntity,
251
339
  buildFolders,
252
340
  buildGitignore,
@@ -257,5 +345,6 @@ function buildZedSettings() {
257
345
  buildSettings,
258
346
  buildTranslations,
259
347
  buildVscodeSettings,
260
- buildZedSettings
348
+ buildZedSettings,
349
+ buildZedTasks
261
350
  });
package/dist/lib.mjs CHANGED
@@ -19,19 +19,48 @@ function buildManifest(opts, moduleId) {
19
19
  if (opts.license) manifest.license = opts.license;
20
20
  if (opts.dependencies.length > 0) {
21
21
  manifest.dependencies = Object.fromEntries(
22
- opts.dependencies.map((d) => [d, ">=0.0.1"])
22
+ opts.dependencies.map(
23
+ (d) => typeof d === "string" ? [d, DEPENDENCY_RANGE] : [d.module, { version: DEPENDENCY_RANGE, entities: d.entities }]
24
+ )
23
25
  );
24
26
  }
25
27
  return manifest;
26
28
  }
29
+ var DEPENDENCY_RANGE = ">=0.0.1";
30
+ function buildDepsContract(dep, consumerCode) {
31
+ return {
32
+ module: dep.module,
33
+ version: DEPENDENCY_RANGE,
34
+ entities: Object.fromEntries(
35
+ dep.entities.map((e) => [
36
+ e,
37
+ { pk: `${e}_id`, use: [`ref:${consumerCode}`] }
38
+ ])
39
+ )
40
+ };
41
+ }
42
+ var NAME_FIELD = "name";
27
43
  function buildEntity(entity) {
28
44
  const traits = entity.traits === "identity+audit" ? ["identity", "audit"] : ["identity"];
29
45
  const built = {
30
46
  description: entity.label,
31
47
  dbObject: entity.name,
32
- toString: "{id}",
48
+ // The traits only add a PK and audit stamps, so an entity with no fields
49
+ // of its own has nothing renderable: its grid view fails the data-view
50
+ // column check and `toString` has nothing to interpolate. Scaffold one
51
+ // visible name column so the module validates and the grid shows a row.
52
+ toString: `{${NAME_FIELD}}`,
33
53
  traits,
34
- fields: {}
54
+ fields: {
55
+ [NAME_FIELD]: {
56
+ dbDatatype: "varchar",
57
+ fieldTypeCd: "text",
58
+ flags: "VEM",
59
+ maxLen: 200,
60
+ orderNum: 10,
61
+ description: "Name"
62
+ }
63
+ }
35
64
  };
36
65
  if (entity.constraints?.length) {
37
66
  built.constraints = Object.fromEntries(
@@ -116,7 +145,8 @@ function buildTranslations(opts) {
116
145
  for (const e of opts.entities) {
117
146
  const fields = {
118
147
  // identity trait → primary key column
119
- [`${e.name}_id`]: { label: `${e.label} ID` }
148
+ [`${e.name}_id`]: { label: `${e.label} ID` },
149
+ [NAME_FIELD]: { label: "Name" }
120
150
  };
121
151
  if (e.traits === "identity+audit") {
122
152
  fields.created_date = { label: "Created Date" };
@@ -157,8 +187,9 @@ function buildTranslations(opts) {
157
187
  }
158
188
  };
159
189
  }
160
- function buildSeedData() {
161
- return [];
190
+ function buildSeedData(entity) {
191
+ const entityCode = typeof entity === "string" ? entity : entity?.name ?? "";
192
+ return { entityCode, records: [] };
162
193
  }
163
194
  function buildGitignore() {
164
195
  return [
@@ -180,34 +211,87 @@ var SCHEMA_BINDINGS = [
180
211
  { fileMatch: ["ui/folders.json"], schema: "folders" },
181
212
  { fileMatch: ["ui/menus.json"], schema: "menus" },
182
213
  { fileMatch: ["ui/reports.json"], schema: "reports" },
214
+ { fileMatch: ["ui/print_templates.json"], schema: "print-templates" },
183
215
  { fileMatch: ["security/roles.json"], schema: "roles" },
184
216
  { fileMatch: ["logic/jobs.json"], schema: "jobs" },
217
+ { fileMatch: ["logic/triggers.json"], schema: "triggers" },
218
+ { fileMatch: ["logic/webhooks.json"], schema: "webhooks" },
219
+ { fileMatch: ["deps/*.json"], schema: "deps" },
185
220
  { fileMatch: ["seed-data/*.json"], schema: "seed-data" },
186
221
  { fileMatch: ["settings.json"], schema: "settings" }
187
222
  ];
223
+ function schemaEntries() {
224
+ return SCHEMA_BINDINGS.map((b) => ({
225
+ fileMatch: b.fileMatch,
226
+ url: `${SCHEMA_BASE}/${b.schema}.schema.json`
227
+ }));
228
+ }
188
229
  function buildVscodeSettings() {
189
- return {
190
- "json.schemas": SCHEMA_BINDINGS.map((b) => ({
191
- fileMatch: b.fileMatch,
192
- url: `${SCHEMA_BASE}/${b.schema}.schema.json`
193
- }))
194
- };
230
+ return { "json.schemas": schemaEntries() };
195
231
  }
196
232
  function buildZedSettings() {
197
233
  return {
198
- languages: {
199
- JSON: {
200
- "json.schemas": SCHEMA_BINDINGS.map((b) => ({
201
- fileMatch: b.fileMatch,
202
- url: `${SCHEMA_BASE}/${b.schema}.schema.json`
203
- }))
234
+ lsp: {
235
+ "json-language-server": {
236
+ settings: { json: { schemas: schemaEntries() } }
237
+ }
238
+ },
239
+ context_servers: {
240
+ dforge: {
241
+ source: "custom",
242
+ command: "npx",
243
+ args: ["-y", "@dforge-core/dforge-mcp@latest"],
244
+ env: {}
204
245
  }
205
246
  }
206
247
  };
207
248
  }
249
+ function buildZedTasks() {
250
+ const CLI = "npx";
251
+ const CLI_ARGS = ["-y", "@dforge-core/dforge-cli@latest"];
252
+ const DEFAULT_TENANT = "http://localhost:5179";
253
+ const task = (label, args) => ({
254
+ label: `dForge: ${label}`,
255
+ command: CLI,
256
+ args: [...CLI_ARGS, ...args],
257
+ cwd: "$ZED_WORKTREE_ROOT",
258
+ env: { DFORGE_URL: DEFAULT_TENANT },
259
+ use_new_terminal: false,
260
+ allow_concurrent_runs: false,
261
+ reveal: "always"
262
+ });
263
+ return [
264
+ task("Pack module", ["module", "pack", "$ZED_WORKTREE_ROOT"]),
265
+ // --force matches the extension's dev-loop default: without it the CLI
266
+ // skips the reinstall when the version hasn't changed and your edits
267
+ // silently never reach the tenant.
268
+ task("Install module to tenant", [
269
+ "module",
270
+ "install",
271
+ "--path",
272
+ "$ZED_WORKTREE_ROOT",
273
+ "--url",
274
+ "$DFORGE_URL",
275
+ "--force"
276
+ ]),
277
+ task("Sign in to tenant", [
278
+ "auth",
279
+ "login",
280
+ "--url",
281
+ "$DFORGE_URL",
282
+ "--login-url",
283
+ "$DFORGE_URL"
284
+ ]),
285
+ task("Show signed-in user", ["auth", "whoami", "--url", "$DFORGE_URL"]),
286
+ task("List installed modules", ["module", "list", "--url", "$DFORGE_URL"])
287
+ ];
288
+ }
208
289
  export {
290
+ DEPENDENCY_RANGE,
291
+ NAME_FIELD,
209
292
  buildActions,
210
293
  buildDataViews,
294
+ buildDepsContract,
211
295
  buildEntity,
212
296
  buildFolders,
213
297
  buildGitignore,
@@ -218,5 +302,6 @@ export {
218
302
  buildSettings,
219
303
  buildTranslations,
220
304
  buildVscodeSettings,
221
- buildZedSettings
305
+ buildZedSettings,
306
+ buildZedTasks
222
307
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dforge-core/dforge-cli",
3
- "version": "0.2.16",
3
+ "version": "0.2.18",
4
4
  "description": "dForge CLI - validate, pack, publish, and install dForge modules. Distributes a single-file native binary per platform via optionalDependencies (esbuild-style).",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/dforge-core/dforge-cli",
@@ -41,11 +41,11 @@
41
41
  "typescript": "^6.0.3"
42
42
  },
43
43
  "optionalDependencies": {
44
- "@dforge-core/dforge-cli-darwin-arm64": "0.2.16",
45
- "@dforge-core/dforge-cli-darwin-x64": "0.2.16",
46
- "@dforge-core/dforge-cli-linux-arm64": "0.2.16",
47
- "@dforge-core/dforge-cli-linux-x64": "0.2.16",
48
- "@dforge-core/dforge-cli-win32-arm64": "0.2.16",
49
- "@dforge-core/dforge-cli-win32-x64": "0.2.16"
44
+ "@dforge-core/dforge-cli-darwin-arm64": "0.2.18",
45
+ "@dforge-core/dforge-cli-darwin-x64": "0.2.18",
46
+ "@dforge-core/dforge-cli-linux-arm64": "0.2.18",
47
+ "@dforge-core/dforge-cli-linux-x64": "0.2.18",
48
+ "@dforge-core/dforge-cli-win32-arm64": "0.2.18",
49
+ "@dforge-core/dforge-cli-win32-x64": "0.2.18"
50
50
  }
51
51
  }