@malloy-publisher/create-malloy-package 0.0.28 → 0.0.30

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 (2) hide show
  1. package/dist/index.js +85 -187
  2. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  // src/index.ts
4
4
  import * as crypto from "node:crypto";
5
- import * as fs5 from "node:fs";
6
- import * as path4 from "node:path";
5
+ import * as fs4 from "node:fs";
6
+ import * as path3 from "node:path";
7
7
  import { fileURLToPath as fileURLToPath2 } from "node:url";
8
8
  import { Command, Option } from "commander";
9
9
 
@@ -406,8 +406,8 @@ function staleScaffolderWarning(running, latest) {
406
406
  }
407
407
 
408
408
  // src/scaffold.ts
409
- import * as fs4 from "node:fs";
410
- import * as path3 from "node:path";
409
+ import * as fs3 from "node:fs";
410
+ import * as path2 from "node:path";
411
411
 
412
412
  // src/config.ts
413
413
  import * as fs from "node:fs";
@@ -528,126 +528,24 @@ function addPackage(config, envName, pkg) {
528
528
  return { added: true, envName: env.name };
529
529
  }
530
530
 
531
+ // src/scaffold.ts
532
+ import { installSkills, isWithinDirectory } from "@malloy-publisher/skills";
533
+
531
534
  // src/skills.ts
532
- import * as fs2 from "node:fs";
533
- import * as path from "node:path";
534
- import { skillsDir } from "@malloy-publisher/skills";
535
+ import { countSkills, skillsDir } from "@malloy-publisher/skills";
535
536
  function assertSkillsAvailable() {
536
537
  if (countSkills(skillsDir) === 0) {
537
538
  throw new ScaffoldError(`No Malloy skills found in ${skillsDir}. The @malloy-publisher/skills ` + `install looks incomplete; reinstall create-malloy-package and run again.`);
538
539
  }
539
540
  }
540
- function installSkills(targetDir, workspaceRoot) {
541
- const empty = { installed: 0, skipped: [], refreshed: [], removed: [] };
542
- if (isSymlink(targetDir)) {
543
- return {
544
- ...empty,
545
- refused: "it is a symlink, so writing into it would edit whatever it points at"
546
- };
547
- }
548
- if (!isWithinDirectory(targetDir, workspaceRoot)) {
549
- return {
550
- ...empty,
551
- refused: "it resolves outside the workspace, so writing into it would put " + "files somewhere else on this machine"
552
- };
553
- }
554
- fs2.mkdirSync(targetDir, { recursive: true });
555
- const skipped = [];
556
- const refreshed = [];
557
- const removed = [];
558
- let installed = 0;
559
- for (const entry of fs2.readdirSync(skillsDir, { withFileTypes: true })) {
560
- if (!entry.isDirectory()) {
561
- continue;
562
- }
563
- const source = path.join(skillsDir, entry.name);
564
- if (!fs2.existsSync(path.join(source, "SKILL.md"))) {
565
- continue;
566
- }
567
- const target = path.join(targetDir, entry.name);
568
- if (isSymlink(target)) {
569
- skipped.push(entry.name);
570
- continue;
571
- }
572
- if (fs2.existsSync(target)) {
573
- refreshed.push(entry.name);
574
- for (const relative of pathsNotIn(target, source)) {
575
- removed.push(path.join(entry.name, relative));
576
- }
577
- }
578
- fs2.rmSync(target, { recursive: true, force: true });
579
- fs2.cpSync(source, target, { recursive: true });
580
- installed += 1;
581
- }
582
- return { installed, skipped, refreshed, removed };
583
- }
584
- function pathsNotIn(target, source, prefix = "") {
585
- let entries;
586
- try {
587
- entries = fs2.readdirSync(path.join(target, prefix), {
588
- withFileTypes: true
589
- });
590
- } catch {
591
- return [];
592
- }
593
- const missing = [];
594
- for (const entry of entries) {
595
- const relative = path.join(prefix, entry.name);
596
- if (!fs2.existsSync(path.join(source, relative))) {
597
- missing.push(entry.isDirectory() ? relative + path.sep : relative);
598
- continue;
599
- }
600
- if (entry.isDirectory()) {
601
- missing.push(...pathsNotIn(target, source, relative));
602
- }
603
- }
604
- return missing;
605
- }
606
- function countSkills(dir) {
607
- if (!fs2.existsSync(dir)) {
608
- return 0;
609
- }
610
- return fs2.readdirSync(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory() && fs2.existsSync(path.join(dir, entry.name, "SKILL.md"))).length;
611
- }
612
- function isWithinDirectory(target, root) {
613
- const realRoot = realPathOf(root);
614
- const realTarget = realPathOf(target);
615
- return realTarget === realRoot || realTarget.startsWith(realRoot + path.sep);
616
- }
617
- function realPathOf(target, hops = 0) {
618
- const resolved = path.resolve(target);
619
- const parent = path.dirname(resolved);
620
- if (parent === resolved) {
621
- return resolved;
622
- }
623
- const here = path.join(realPathOf(parent, hops), path.basename(resolved));
624
- if (hops >= 40) {
625
- return here;
626
- }
627
- try {
628
- if (!fs2.lstatSync(here).isSymbolicLink()) {
629
- return here;
630
- }
631
- return realPathOf(path.resolve(path.dirname(here), fs2.readlinkSync(here)), hops + 1);
632
- } catch {
633
- return here;
634
- }
635
- }
636
- function isSymlink(target) {
637
- try {
638
- return fs2.lstatSync(target).isSymbolicLink();
639
- } catch {
640
- return false;
641
- }
642
- }
643
541
 
644
542
  // src/templates.ts
645
- import * as fs3 from "node:fs";
646
- import * as path2 from "node:path";
543
+ import * as fs2 from "node:fs";
544
+ import * as path from "node:path";
647
545
  import { fileURLToPath } from "node:url";
648
- var templatesDir = path2.resolve(path2.dirname(fileURLToPath(import.meta.url)), "..", "templates");
546
+ var templatesDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "templates");
649
547
  function renderTemplate(name, vars) {
650
- const raw = fs3.readFileSync(path2.join(templatesDir, name), "utf8");
548
+ const raw = fs2.readFileSync(path.join(templatesDir, name), "utf8");
651
549
  const referenced = new Set;
652
550
  const rendered = raw.replace(/\{\{(\w+)\}\}/g, (_match, key) => {
653
551
  if (!(key in vars)) {
@@ -675,7 +573,7 @@ var MCP_PORT = 4040;
675
573
  var ALT_PUBLISHER_PORT = PUBLISHER_PORT + 100;
676
574
  var ALT_MCP_PORT = MCP_PORT + 100;
677
575
  var BIND_HOST = "127.0.0.1";
678
- var SERVER_VERSION = "0.9.2";
576
+ var SERVER_VERSION = "0.9.4";
679
577
  function startCommandFor(envName) {
680
578
  return `npx -y @malloy-publisher/server@${SERVER_VERSION} --server_root . ` + `--config ./publisher.config.json --host ${BIND_HOST} ` + `--watch-env ${envName}`;
681
579
  }
@@ -746,8 +644,8 @@ function scaffold(options) {
746
644
  mcpEntryReplaced: false,
747
645
  skillsInstalled: 0
748
646
  };
749
- const configPath = path3.join(options.cwd, "publisher.config.json");
750
- const configExists = fs4.existsSync(configPath);
647
+ const configPath = path2.join(options.cwd, "publisher.config.json");
648
+ const configExists = fs3.existsSync(configPath);
751
649
  const config = configExists ? readConfig(configPath) : defaultConfig(ENV_NAME);
752
650
  const targetEnv = targetEnvironment(config, ENV_NAME);
753
651
  if (targetEnv !== undefined) {
@@ -774,9 +672,9 @@ function createPackage(options, result) {
774
672
  const sourceName = toMalloyIdentifier(name);
775
673
  const modelIsIndex = sourceName.toLowerCase() === "index";
776
674
  const modelFile = modelIsIndex ? INDEX_MODEL_NAME : `${sourceName}.malloy`;
777
- const packageDir = path3.join(options.cwd, name);
778
- const packageDirExists = fs4.existsSync(packageDir);
779
- if (packageDirExists && !fs4.lstatSync(packageDir).isDirectory()) {
675
+ const packageDir = path2.join(options.cwd, name);
676
+ const packageDirExists = fs3.existsSync(packageDir);
677
+ if (packageDirExists && !fs3.lstatSync(packageDir).isDirectory()) {
780
678
  throw new ScaffoldError(`"${name}" already exists here and is not a directory, so the package ` + `cannot be created there. --force does not help: it overwrites files ` + `inside a package directory, it does not replace something that is ` + `in the way.
781
679
 
782
680
  ` + `Choose another name, or move or remove "${name}" first.`);
@@ -789,25 +687,25 @@ function createPackage(options, result) {
789
687
  ` + `If you passed --force to \`npm create\`, npm read it as one of its ` + `own settings and it never reached this tool. Options need a \`--\` ` + `in front of them there:
790
688
  ` + ` npm create @malloy-publisher/malloy-package@latest ${name} -- --force`);
791
689
  }
792
- const dataDir = path3.join(packageDir, "data");
690
+ const dataDir = path2.join(packageDir, "data");
793
691
  assertWithinWorkspace(dataDir, options.cwd, `${name}/data`);
794
- fs4.mkdirSync(dataDir, { recursive: true });
795
- writeFile(path3.join(packageDir, "publisher.json"), JSON.stringify({ name }, null, 2) + `
692
+ fs3.mkdirSync(dataDir, { recursive: true });
693
+ writeFile(path2.join(packageDir, "publisher.json"), JSON.stringify({ name }, null, 2) + `
796
694
  `, options.cwd);
797
- writeFile(path3.join(packageDir, "malloy-config.json"), JSON.stringify({
695
+ writeFile(path2.join(packageDir, "malloy-config.json"), JSON.stringify({
798
696
  connections: {
799
697
  duckdb: {
800
698
  is: "duckdb",
801
- workingDirectory: path3.resolve(packageDir)
699
+ workingDirectory: path2.resolve(packageDir)
802
700
  }
803
701
  }
804
702
  }, null, 2) + `
805
703
  `, options.cwd);
806
704
  let dataPath;
807
705
  if (options.dataFile !== undefined) {
808
- const sourceBase = path3.basename(options.dataFile);
706
+ const sourceBase = path2.basename(options.dataFile);
809
707
  const destBase = sanitizeFileName(sourceBase);
810
- copyFile(options.dataFile, path3.join(dataDir, destBase), options.cwd, `${name}/data/${destBase}`);
708
+ copyFile(options.dataFile, path2.join(dataDir, destBase), options.cwd, `${name}/data/${destBase}`);
811
709
  dataPath = `data/${destBase}`;
812
710
  if (destBase !== sourceBase) {
813
711
  result.dataFileRenamedFrom = sourceBase;
@@ -816,14 +714,14 @@ function createPackage(options, result) {
816
714
  if (siblings.length > 0) {
817
715
  result.siblingDataFiles = siblings;
818
716
  }
819
- writeFile(path3.join(packageDir, modelFile), renderTemplate(isSpreadsheet(dataPath) ? "model.custom.xlsx.malloy" : "model.custom.malloy", { sourceName, dataPath }), options.cwd);
717
+ writeFile(path2.join(packageDir, modelFile), renderTemplate(isSpreadsheet(dataPath) ? "model.custom.xlsx.malloy" : "model.custom.malloy", { sourceName, dataPath }), options.cwd);
820
718
  } else {
821
- copyFile(path3.join(templatesDir, "sales.csv"), path3.join(dataDir, "sales.csv"), options.cwd, `${name}/data/sales.csv`);
719
+ copyFile(path2.join(templatesDir, "sales.csv"), path2.join(dataDir, "sales.csv"), options.cwd, `${name}/data/sales.csv`);
822
720
  dataPath = "data/sales.csv";
823
- writeFile(path3.join(packageDir, modelFile), renderTemplate("model.default.malloy", { sourceName }), options.cwd);
721
+ writeFile(path2.join(packageDir, modelFile), renderTemplate("model.default.malloy", { sourceName }), options.cwd);
824
722
  }
825
723
  if (!modelIsIndex) {
826
- writeFile(path3.join(packageDir, INDEX_MODEL_NAME), renderTemplate(INDEX_MODEL_NAME, { sourceName, modelFile }), options.cwd);
724
+ writeFile(path2.join(packageDir, INDEX_MODEL_NAME), renderTemplate(INDEX_MODEL_NAME, { sourceName, modelFile }), options.cwd);
827
725
  }
828
726
  result.packageCreated = true;
829
727
  result.packageName = name;
@@ -862,7 +760,7 @@ function wireWorkspace(options, config, configExists, configPath, packageEntry,
862
760
  } else {
863
761
  result.skipped.push("publisher.config.json");
864
762
  }
865
- result.needsReset = result.packageCreated && (fs4.existsSync(path3.join(cwd, "publisher_data")) || fs4.existsSync(path3.join(cwd, "publisher.db")));
763
+ result.needsReset = result.packageCreated && (fs3.existsSync(path2.join(cwd, "publisher_data")) || fs3.existsSync(path2.join(cwd, "publisher.db")));
866
764
  result.startCommand = startCommandFor(result.envName);
867
765
  result.resetCommand = resetCommandFor(result.envName);
868
766
  writeWorkspacePackageJson(cwd, options, result);
@@ -884,8 +782,8 @@ function wireWorkspace(options, config, configExists, configPath, packageEntry,
884
782
  function writeAgentsFile(cwd, content, options, result) {
885
783
  assertBriefingIsRecognisable(content);
886
784
  const relPath = "AGENTS.md";
887
- const target = path3.join(cwd, relPath);
888
- const exists = fs4.existsSync(target);
785
+ const target = path2.join(cwd, relPath);
786
+ const exists = fs3.existsSync(target);
889
787
  const ours = exists && isGeneratedBriefing(target);
890
788
  if (!exists || ours || options.force) {
891
789
  writeFile(target, content, cwd);
@@ -895,14 +793,14 @@ function writeAgentsFile(cwd, content, options, result) {
895
793
  } else if (exists) {
896
794
  result.replaced.push(relPath);
897
795
  }
898
- if (fs4.existsSync(path3.join(cwd, MALLOY_AGENTS_FILE))) {
796
+ if (fs3.existsSync(path2.join(cwd, MALLOY_AGENTS_FILE))) {
899
797
  result.skipped.push(`${MALLOY_AGENTS_FILE} (left from an earlier run, when AGENTS.md ` + `was not ours to write; AGENTS.md now holds the briefing, so ` + `this copy is stale and can be deleted)`);
900
798
  }
901
799
  return;
902
800
  }
903
801
  result.skipped.push(relPath);
904
- const existed = fs4.existsSync(path3.join(cwd, MALLOY_AGENTS_FILE));
905
- writeFile(path3.join(cwd, MALLOY_AGENTS_FILE), content, cwd);
802
+ const existed = fs3.existsSync(path2.join(cwd, MALLOY_AGENTS_FILE));
803
+ writeFile(path2.join(cwd, MALLOY_AGENTS_FILE), content, cwd);
906
804
  result.agentsFile = MALLOY_AGENTS_FILE;
907
805
  result.written.push(`${MALLOY_AGENTS_FILE} (the Publisher briefing, because this ` + `directory's own AGENTS.md was left alone)`);
908
806
  if (existed) {
@@ -911,7 +809,7 @@ function writeAgentsFile(cwd, content, options, result) {
911
809
  }
912
810
  function isGeneratedBriefing(target) {
913
811
  try {
914
- return fs4.readFileSync(target, "utf8").includes(BRIEFING_MARKER);
812
+ return fs3.readFileSync(target, "utf8").includes(BRIEFING_MARKER);
915
813
  } catch {
916
814
  return false;
917
815
  }
@@ -922,27 +820,27 @@ function assertBriefingIsRecognisable(content) {
922
820
  }
923
821
  }
924
822
  function installWorkspaceSkills(cwd, result) {
925
- const relDir = path3.join(".claude", "skills");
926
- const skills = installSkills(path3.join(cwd, relDir), cwd);
823
+ const relDir = path2.join(".claude", "skills");
824
+ const skills = installSkills(path2.join(cwd, relDir), cwd);
927
825
  result.skillsInstalled = skills.installed;
928
826
  if (skills.refused) {
929
- result.skipped.push(`${relDir}${path3.sep} (${skills.refused}; no skills were installed)`);
827
+ result.skipped.push(`${relDir}${path2.sep} (${skills.refused}; no skills were installed)`);
930
828
  }
931
829
  for (const name of skills.skipped) {
932
- result.skipped.push(`${path3.join(relDir, name)} (symlink, not written through)`);
830
+ result.skipped.push(`${path2.join(relDir, name)} (symlink, not written through)`);
933
831
  }
934
832
  if (skills.refreshed.length > 0) {
935
833
  const count = skills.refreshed.length;
936
- result.replaced.push(`${relDir}${path3.sep} (${count} skill${count === 1 ? "" : "s"} ` + `refreshed: every run deletes each skill directory and writes the ` + `bundled copy back, so edits to a skill are reverted and anything ` + `else you put inside one is removed, not just changed)`);
834
+ result.replaced.push(`${relDir}${path2.sep} (${count} skill${count === 1 ? "" : "s"} ` + `refreshed: every run deletes each skill directory and writes the ` + `bundled copy back, so edits to a skill are reverted and anything ` + `else you put inside one is removed, not just changed)`);
937
835
  }
938
836
  if (skills.removed.length > 0) {
939
- const shown2 = skills.removed.slice(0, 5).map((entry) => printable(path3.join(relDir, entry)));
837
+ const shown2 = skills.removed.slice(0, 5).map((entry) => printable(path2.join(relDir, entry)));
940
838
  const rest = skills.removed.length - shown2.length;
941
839
  result.replaced.push(`${shown2.join(", ")}${rest > 0 ? `, and ${rest} more` : ""} (not ` + `part of any bundled skill, so nothing wrote ` + `${shown2.length === 1 && rest === 0 ? "it" : "them"} back)`);
942
840
  }
943
841
  }
944
842
  function assertServablePath(cwd) {
945
- const absolute = path3.resolve(cwd);
843
+ const absolute = path2.resolve(cwd);
946
844
  for (const character of absolute) {
947
845
  if (!isServablePathCharacter(character)) {
948
846
  const codePoint = character.codePointAt(0);
@@ -977,7 +875,7 @@ function assertWorkspacePathsContained(options, mcpConfigPath) {
977
875
  relatives.push(options.name);
978
876
  }
979
877
  for (const relative2 of relatives) {
980
- assertWithinWorkspace(path3.join(options.cwd, relative2), options.cwd, relative2);
878
+ assertWithinWorkspace(path2.join(options.cwd, relative2), options.cwd, relative2);
981
879
  }
982
880
  }
983
881
  function assertWithinWorkspace(target, root, label) {
@@ -991,13 +889,13 @@ function assertNotReservedName(name) {
991
889
  }
992
890
  }
993
891
  function readWorkspacePackageJson(cwd) {
994
- const target = path3.join(cwd, "package.json");
995
- if (!fs4.existsSync(target)) {
892
+ const target = path2.join(cwd, "package.json");
893
+ if (!fs3.existsSync(target)) {
996
894
  return { kind: "absent" };
997
895
  }
998
896
  let text;
999
897
  try {
1000
- text = fs4.readFileSync(target, "utf8");
898
+ text = fs3.readFileSync(target, "utf8");
1001
899
  } catch (err) {
1002
900
  return {
1003
901
  kind: "unusable",
@@ -1262,7 +1160,7 @@ function readMergeablePackageJson(cwd) {
1262
1160
  }
1263
1161
  function writeWorkspacePackageJson(cwd, options, result) {
1264
1162
  const relPath = "package.json";
1265
- const target = path3.join(cwd, relPath);
1163
+ const target = path2.join(cwd, relPath);
1266
1164
  const manifest = readWorkspacePackageJson(cwd);
1267
1165
  if (manifest.kind === "absent") {
1268
1166
  writeFile(target, workspacePackageJson(cwd, result), cwd);
@@ -1296,8 +1194,8 @@ function writeWorkspacePackageJson(cwd, options, result) {
1296
1194
  }
1297
1195
  }
1298
1196
  function writeMcpConfig(cwd, relPath, result) {
1299
- const target = path3.join(cwd, relPath);
1300
- if (!fs4.existsSync(target)) {
1197
+ const target = path2.join(cwd, relPath);
1198
+ if (!fs3.existsSync(target)) {
1301
1199
  writeFile(target, mcpConfig(), cwd);
1302
1200
  result.written.push(relPath);
1303
1201
  result.mcpWired = true;
@@ -1306,7 +1204,7 @@ function writeMcpConfig(cwd, relPath, result) {
1306
1204
  let parsed;
1307
1205
  let parses = true;
1308
1206
  try {
1309
- parsed = parseJson(fs4.readFileSync(target, "utf8"));
1207
+ parsed = parseJson(fs3.readFileSync(target, "utf8"));
1310
1208
  } catch {
1311
1209
  parses = false;
1312
1210
  }
@@ -1439,7 +1337,7 @@ function isNameableHere(name) {
1439
1337
  }
1440
1338
  function workspacePackageJson(cwd, result) {
1441
1339
  return JSON.stringify({
1442
- name: toNpmName(path3.basename(path3.resolve(cwd))),
1340
+ name: toNpmName(path2.basename(path2.resolve(cwd))),
1443
1341
  version: "0.1.0",
1444
1342
  private: true,
1445
1343
  engines: {
@@ -1469,8 +1367,8 @@ function workspaceGitignore() {
1469
1367
  }
1470
1368
  function mergeGitignore(cwd, result) {
1471
1369
  const relPath = ".gitignore";
1472
- const target = path3.join(cwd, relPath);
1473
- if (!fs4.existsSync(target)) {
1370
+ const target = path2.join(cwd, relPath);
1371
+ if (!fs3.existsSync(target)) {
1474
1372
  writeFile(target, workspaceGitignore(), cwd);
1475
1373
  result.written.push(relPath);
1476
1374
  return;
@@ -1478,7 +1376,7 @@ function mergeGitignore(cwd, result) {
1478
1376
  assertWithinWorkspace(target, cwd, relPath);
1479
1377
  let existing;
1480
1378
  try {
1481
- existing = fs4.readFileSync(target, "utf8");
1379
+ existing = fs3.readFileSync(target, "utf8");
1482
1380
  } catch (err) {
1483
1381
  result.skipped.push(`${relPath} (could not be read, so Publisher's files are not ` + `ignored here: ${err.message})`);
1484
1382
  return;
@@ -1494,7 +1392,7 @@ function mergeGitignore(cwd, result) {
1494
1392
  ` : `
1495
1393
 
1496
1394
  `;
1497
- fs4.appendFileSync(target, `${prefix}${GITIGNORE_HEADER}
1395
+ fs3.appendFileSync(target, `${prefix}${GITIGNORE_HEADER}
1498
1396
  ${missing.join(`
1499
1397
  `)}
1500
1398
  `);
@@ -1533,27 +1431,27 @@ var LOADABLE_DATA_EXTENSIONS = [
1533
1431
  ".xlsx"
1534
1432
  ];
1535
1433
  function isLoadableDataFile(file) {
1536
- return LOADABLE_DATA_EXTENSIONS.includes(path3.extname(file).toLowerCase());
1434
+ return LOADABLE_DATA_EXTENSIONS.includes(path2.extname(file).toLowerCase());
1537
1435
  }
1538
1436
  function isSpreadsheet(dataPath) {
1539
- return path3.extname(dataPath).toLowerCase() === ".xlsx";
1437
+ return path2.extname(dataPath).toLowerCase() === ".xlsx";
1540
1438
  }
1541
1439
  function validateDataFile(dataFile) {
1542
- if (!fs4.existsSync(dataFile) || !fs4.statSync(dataFile).isFile()) {
1440
+ if (!fs3.existsSync(dataFile) || !fs3.statSync(dataFile).isFile()) {
1543
1441
  throw new ScaffoldError(`--data file not found: ${printable(dataFile)}`);
1544
1442
  }
1545
1443
  if (!isLoadableDataFile(dataFile)) {
1546
- throw new ScaffoldError(`--data must be one of ${LOADABLE_DATA_EXTENSIONS.join(", ")} (got "${printable(path3.basename(dataFile))}").`);
1444
+ throw new ScaffoldError(`--data must be one of ${LOADABLE_DATA_EXTENSIONS.join(", ")} (got "${printable(path2.basename(dataFile))}").`);
1547
1445
  }
1548
1446
  }
1549
1447
  function findSiblingDataFiles(dataFile) {
1550
1448
  let entries;
1551
1449
  try {
1552
- entries = fs4.readdirSync(path3.dirname(dataFile));
1450
+ entries = fs3.readdirSync(path2.dirname(dataFile));
1553
1451
  } catch {
1554
1452
  return [];
1555
1453
  }
1556
- const chosen = path3.basename(dataFile);
1454
+ const chosen = path2.basename(dataFile);
1557
1455
  return entries.filter((e) => e !== chosen && isLoadableDataFile(e)).sort().map(printable);
1558
1456
  }
1559
1457
  function toNpmName(base) {
@@ -1564,8 +1462,8 @@ function sanitizeFileName(base) {
1564
1462
  return base.replace(/[^A-Za-z0-9._-]/g, "_");
1565
1463
  }
1566
1464
  function writeIfAbsent(cwd, relPath, content, options, result) {
1567
- const target = path3.join(cwd, relPath);
1568
- const exists = fs4.existsSync(target);
1465
+ const target = path2.join(cwd, relPath);
1466
+ const exists = fs3.existsSync(target);
1569
1467
  if (exists && !options.force) {
1570
1468
  result.skipped.push(relPath);
1571
1469
  return false;
@@ -1578,20 +1476,20 @@ function writeIfAbsent(cwd, relPath, content, options, result) {
1578
1476
  return true;
1579
1477
  }
1580
1478
  function writeFile(target, content, root) {
1581
- assertWithinWorkspace(target, root, path3.relative(root, target) || target);
1582
- fs4.mkdirSync(path3.dirname(target), { recursive: true });
1583
- fs4.writeFileSync(target, content);
1479
+ assertWithinWorkspace(target, root, path2.relative(root, target) || target);
1480
+ fs3.mkdirSync(path2.dirname(target), { recursive: true });
1481
+ fs3.writeFileSync(target, content);
1584
1482
  }
1585
1483
  function copyFile(source, target, root, label) {
1586
1484
  assertWithinWorkspace(target, root, label);
1587
- fs4.copyFileSync(source, target);
1485
+ fs3.copyFileSync(source, target);
1588
1486
  }
1589
1487
 
1590
1488
  // src/index.ts
1591
1489
  var CLIENTS = ["claude-code", "cursor"];
1592
1490
  function version() {
1593
1491
  try {
1594
- const pkg = JSON.parse(fs5.readFileSync(new URL("../package.json", import.meta.url), "utf8"));
1492
+ const pkg = JSON.parse(fs4.readFileSync(new URL("../package.json", import.meta.url), "utf8"));
1595
1493
  return typeof pkg.version === "string" ? pkg.version : "unknown";
1596
1494
  } catch {
1597
1495
  return "unknown";
@@ -1607,7 +1505,7 @@ function resolveDataFile(cwd, data) {
1607
1505
  if (data.trim() === "") {
1608
1506
  throw new ScaffoldError(`--data was given an empty filename. Pass the CSV, Parquet, JSON, NDJSON, or XLSX ` + `file to seed the package from, or leave --data off to use the ` + `sample data.`);
1609
1507
  }
1610
- return path4.resolve(cwd, data);
1508
+ return path3.resolve(cwd, data);
1611
1509
  }
1612
1510
  async function run(name, options) {
1613
1511
  const cwd = process.cwd();
@@ -1648,11 +1546,11 @@ function artifactCandidates(name) {
1648
1546
  "publisher.config.json",
1649
1547
  "package.json",
1650
1548
  ".mcp.json",
1651
- path4.join(".cursor", "mcp.json"),
1549
+ path3.join(".cursor", "mcp.json"),
1652
1550
  ".gitignore",
1653
1551
  "AGENTS.md",
1654
1552
  "CLAUDE.md",
1655
- path4.join(".claude", "skills")
1553
+ path3.join(".claude", "skills")
1656
1554
  ];
1657
1555
  if (name !== undefined && name !== "" && name !== "." && name !== ".." && !name.includes("/") && !name.includes("\\")) {
1658
1556
  paths.unshift(name);
@@ -1683,10 +1581,10 @@ function changesSince(cwd, name, before) {
1683
1581
  return changes;
1684
1582
  }
1685
1583
  function fingerprint(cwd, relPath) {
1686
- const target = path4.join(cwd, relPath);
1584
+ const target = path3.join(cwd, relPath);
1687
1585
  let stat;
1688
1586
  try {
1689
- stat = fs5.lstatSync(target);
1587
+ stat = fs4.lstatSync(target);
1690
1588
  } catch {
1691
1589
  return;
1692
1590
  }
@@ -1695,7 +1593,7 @@ function fingerprint(cwd, relPath) {
1695
1593
  return `dir:${digest(listDirectory(target))}`;
1696
1594
  }
1697
1595
  if (stat.isFile()) {
1698
- return `file:${digest(fs5.readFileSync(target))}`;
1596
+ return `file:${digest(fs4.readFileSync(target))}`;
1699
1597
  }
1700
1598
  return `other:${stat.mode}:${linkTarget(target)}`;
1701
1599
  } catch {
@@ -1709,13 +1607,13 @@ function listDirectory(dir, cap = 5000) {
1709
1607
  const current = stack.pop();
1710
1608
  let children;
1711
1609
  try {
1712
- children = fs5.readdirSync(current, { withFileTypes: true });
1610
+ children = fs4.readdirSync(current, { withFileTypes: true });
1713
1611
  } catch {
1714
- entries.push(`${path4.relative(dir, current)} unreadable`);
1612
+ entries.push(`${path3.relative(dir, current)} unreadable`);
1715
1613
  continue;
1716
1614
  }
1717
1615
  for (const child of children) {
1718
- const full = path4.join(current, child.name);
1616
+ const full = path3.join(current, child.name);
1719
1617
  if (child.isDirectory()) {
1720
1618
  stack.push(full);
1721
1619
  continue;
@@ -1723,11 +1621,11 @@ function listDirectory(dir, cap = 5000) {
1723
1621
  let size = -1;
1724
1622
  let mtime = -1;
1725
1623
  try {
1726
- const childStat = fs5.lstatSync(full);
1624
+ const childStat = fs4.lstatSync(full);
1727
1625
  size = childStat.size;
1728
1626
  mtime = childStat.mtimeMs;
1729
1627
  } catch {}
1730
- entries.push(`${path4.relative(dir, full)} ${size} ${mtime}`);
1628
+ entries.push(`${path3.relative(dir, full)} ${size} ${mtime}`);
1731
1629
  }
1732
1630
  }
1733
1631
  entries.sort();
@@ -1736,7 +1634,7 @@ function listDirectory(dir, cap = 5000) {
1736
1634
  }
1737
1635
  function linkTarget(target) {
1738
1636
  try {
1739
- return fs5.readlinkSync(target);
1637
+ return fs4.readlinkSync(target);
1740
1638
  } catch {
1741
1639
  return "";
1742
1640
  }
@@ -1815,12 +1713,12 @@ function describeFailure(err) {
1815
1713
  return String(err);
1816
1714
  }
1817
1715
  function relativeToCwd(target) {
1818
- const relative3 = path4.relative(process.cwd(), target);
1819
- return relative3 && !relative3.startsWith("..") && !path4.isAbsolute(relative3) ? `./${relative3}` : target;
1716
+ const relative3 = path3.relative(process.cwd(), target);
1717
+ return relative3 && !relative3.startsWith("..") && !path3.isAbsolute(relative3) ? `./${relative3}` : target;
1820
1718
  }
1821
1719
  function readWorkspaceFile(cwd, relPath) {
1822
1720
  try {
1823
- return fs5.readFileSync(path4.join(cwd, relPath), "utf8");
1721
+ return fs4.readFileSync(path3.join(cwd, relPath), "utf8");
1824
1722
  } catch {
1825
1723
  return;
1826
1724
  }
@@ -2160,7 +2058,7 @@ function startedAsProgram() {
2160
2058
  return true;
2161
2059
  }
2162
2060
  try {
2163
- return fs5.realpathSync(entry) === fs5.realpathSync(fileURLToPath2(import.meta.url));
2061
+ return fs4.realpathSync(entry) === fs4.realpathSync(fileURLToPath2(import.meta.url));
2164
2062
  } catch {
2165
2063
  return true;
2166
2064
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@malloy-publisher/create-malloy-package",
3
3
  "description": "Scaffold a Malloy Publisher package and a local agent workspace, so one command takes you from nothing to an agent that can query your data.",
4
- "version": "0.0.28",
4
+ "version": "0.0.30",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "engines": {
@@ -45,12 +45,12 @@
45
45
  "test:e2e": "bun test --timeout 180000 ./tests/e2e"
46
46
  },
47
47
  "dependencies": {
48
- "@malloy-publisher/skills": "^0.1.34",
48
+ "@malloy-publisher/skills": "^0.1.35",
49
49
  "commander": "^12.1.0"
50
50
  },
51
51
  "devDependencies": {
52
52
  "@eslint/js": "^8.57.0",
53
- "@malloydata/malloy": "^0.0.434",
53
+ "@malloydata/malloy": "^0.0.435",
54
54
  "@modelcontextprotocol/sdk": "^1.31.0",
55
55
  "@types/bun": "^1.2.21",
56
56
  "@types/node": "^24.10.0",
@@ -59,5 +59,5 @@
59
59
  "eslint": "^8.50.0",
60
60
  "typescript": "^5.3.3"
61
61
  },
62
- "publisherServer": "0.9.2"
62
+ "publisherServer": "0.9.4"
63
63
  }