@zebralabs/context-cli 0.1.5 → 0.1.7

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/package.json +1 -1
  2. package/src/context.js +62 -7
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zebralabs/context-cli",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "Context-as-Code CLI (help/list/compile/validate)",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/src/context.js CHANGED
@@ -23,10 +23,14 @@ Usage:
23
23
 
24
24
  Pack install:
25
25
  ctx pack install <packId> [--repo-root <path>] [--mode SkipExisting|Overwrite]
26
+ [--install-option KEY=VALUE] ...
26
27
  ([--zip <path>] | [--registry <url> [--version <x.y.z>] --token <token>])
27
28
 
29
+ Install options are pack-specific (e.g. --install-option Flavour=ReviewOnly). See the pack's INSTALLATION.md for supported options.
30
+
28
31
  Examples (local zip test):
29
32
  ctx pack install pack-01-documentation-management --zip D:\\packs\\pack-01-documentation-management-v0.1.0.zip
33
+ ctx pack install pack-01-documentation-management --zip <path> --install-option Flavour=ReviewOnly
30
34
 
31
35
  Examples (registry download):
32
36
  ctx pack install pack-01-documentation-management --registry https://example.com --token YOURTOKEN
@@ -520,6 +524,31 @@ function ensureDir(p) {
520
524
  fs.mkdirSync(p, { recursive: true });
521
525
  }
522
526
 
527
+ /**
528
+ * After pack install: ensure docs/local/ exists and .gitignore has /docs/local/
529
+ * (create .gitignore if missing; append entry if present but pattern not found).
530
+ */
531
+ function ensureDocsLocalAndGitignore(repoRoot) {
532
+ const docsLocalDir = path.join(repoRoot, "docs", "local");
533
+ ensureDir(docsLocalDir);
534
+
535
+ const gitignorePath = path.join(repoRoot, ".gitignore");
536
+ const entry = "\n# Local-only documentation (excluded from AI context and version control)\n/docs/local/\n";
537
+ const pattern = "/docs/local/";
538
+
539
+ if (!fs.existsSync(gitignorePath)) {
540
+ fs.writeFileSync(gitignorePath, entry.trimStart(), "utf8");
541
+ return;
542
+ }
543
+
544
+ const content = fs.readFileSync(gitignorePath, "utf8");
545
+ if (content.includes(pattern) || content.includes("docs/local/")) return;
546
+
547
+ const trimmed = content.trimEnd();
548
+ const suffix = trimmed.endsWith("\n") ? entry : "\n" + entry;
549
+ fs.writeFileSync(gitignorePath, trimmed + suffix, "utf8");
550
+ }
551
+
523
552
  function writeYamlFile(filePath, obj) {
524
553
  const text = YAML.stringify(obj, { indent: 2 });
525
554
  fs.writeFileSync(filePath, text.endsWith("\n") ? text : (text + "\n"), "utf8");
@@ -712,11 +741,24 @@ async function cmdPackInstall(repoRoot, packId, opts) {
712
741
  if (!version) version = "0.0.0";
713
742
  }
714
743
 
715
- // Run installer
716
- console.log(`Installing (mode=${mode})...`);
717
- const installCmd = `& "${installer}" -TargetRoot "${repoRoot}" -PackId "${packId}" -Mode "${mode}"`;
744
+ // Run installer: fixed args + pack-specific install options (passed through as -Key "Value")
745
+ const installOpts = opts.installOptions || [];
746
+ const escapePsQuoted = (s) => (s || "").replace(/`/g, "``").replace(/"/g, '`"');
747
+ let installArgs = `-TargetRoot "${escapePsQuoted(repoRoot)}" -PackId "${escapePsQuoted(packId)}" -Mode "${mode}"`;
748
+ for (const pair of installOpts) {
749
+ const eq = pair.indexOf("=");
750
+ const key = pair.slice(0, eq).trim();
751
+ const value = (pair.slice(eq + 1) || "").trim();
752
+ const psKey = toPascalCase(key);
753
+ installArgs += ` -${psKey} "${escapePsQuoted(value)}"`;
754
+ }
755
+ console.log(`Installing (mode=${mode}${installOpts.length ? ", " + installOpts.length + " install option(s)" : ""})...`);
756
+ const installCmd = `& "${escapePsQuoted(installer)}" ${installArgs}`;
718
757
  runPwsh(installCmd, { cwd: extractDir });
719
758
 
759
+ // Ensure docs/local/ exists and .gitignore has /docs/local/
760
+ ensureDocsLocalAndGitignore(repoRoot);
761
+
720
762
  // Update context.yaml (safe read + repair)
721
763
  let ctx2 = readYamlFileSafe(ctxPath);
722
764
  if (!ctx2) {
@@ -749,8 +791,17 @@ async function cmdPackInstall(repoRoot, packId, opts) {
749
791
  }
750
792
  }
751
793
 
794
+ /** Convert install-option key to PowerShell PascalCase param name (e.g. flavour -> Flavour, some-key -> SomeKey). */
795
+ function toPascalCase(key) {
796
+ if (!key || typeof key !== "string") return key;
797
+ return key
798
+ .split(/[-_]/)
799
+ .map((s) => (s.charAt(0).toUpperCase() + s.slice(1).toLowerCase()))
800
+ .join("");
801
+ }
802
+
752
803
  function parseOpts(args) {
753
- const opts = {};
804
+ const opts = { installOptions: [] };
754
805
  for (let i = 0; i < args.length; i++) {
755
806
  const a = args[i];
756
807
  if (a === "--token") opts.token = args[++i];
@@ -759,7 +810,11 @@ function parseOpts(args) {
759
810
  else if (a === "--zip") opts.zip = args[++i];
760
811
  else if (a === "--mode") opts.mode = args[++i];
761
812
  else if (a === "--repo-root") opts.repoRoot = args[++i];
762
- else die(`Unknown option: ${a}`);
813
+ else if (a === "--install-option") {
814
+ const pair = args[++i];
815
+ if (!pair || !pair.includes("=")) die("--install-option requires KEY=VALUE (e.g. Flavour=ReviewOnly)");
816
+ opts.installOptions.push(pair);
817
+ } else die(`Unknown option: ${a}`);
763
818
  }
764
819
  return opts;
765
820
  }
@@ -772,7 +827,7 @@ async function main() {
772
827
 
773
828
  if (cmd === "--version" || cmd === "-v" || cmd === "version") {
774
829
  // Make sure package.json has version (or hardcode a constant)
775
- console.log("0.1.5");
830
+ console.log("0.1.7");
776
831
  return;
777
832
  }
778
833
 
@@ -785,7 +840,7 @@ async function main() {
785
840
  }
786
841
 
787
842
  const packId = process.argv[4];
788
- if (!packId) die("Usage: ctx pack install <packId> [--zip <path>] | [--registry <url> --token <token> ...]");
843
+ if (!packId) die("Usage: ctx pack install <packId> [--zip <path>] [--install-option KEY=VALUE ...] | [--registry <url> --token <token> ...]");
789
844
 
790
845
  const opts = parseOpts(process.argv.slice(5));
791
846