@promptscript/cli 1.1.0 → 1.2.0

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/CHANGELOG.md CHANGED
@@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.2.0](https://github.com/mrwogu/promptscript/compare/v1.1.0...v1.2.0) (2026-03-11)
9
+
10
+
11
+ ### Features
12
+
13
+ * **formatters:** add Factory AI droids support (.factory/droids/) ([#94](https://github.com/mrwogu/promptscript/issues/94)) ([e7f9292](https://github.com/mrwogu/promptscript/commit/e7f929273254738b2de5334f26136c8374aedc7b))
14
+
15
+
16
+ ### Bug Fixes
17
+
18
+ * **cli:** handle skill resource files without PromptScript markers ([#92](https://github.com/mrwogu/promptscript/issues/92)) ([3153498](https://github.com/mrwogu/promptscript/commit/315349865335cc1013b5c60d5c418885bf6467f8))
19
+
8
20
  ## [1.1.0](https://github.com/mrwogu/promptscript/compare/v1.0.0...v1.1.0) (2026-03-11)
9
21
 
10
22
 
package/index.js CHANGED
@@ -3331,6 +3331,7 @@ var MarkdownInstructionFormatter = class extends BaseFormatter {
3331
3331
  this.addSection(sections, this.postWork(ast, renderer));
3332
3332
  this.addSection(sections, this.documentation(ast, renderer));
3333
3333
  this.addSection(sections, this.diagrams(ast, renderer));
3334
+ this.addSection(sections, this.knowledgeContent(ast, renderer));
3334
3335
  this.addSection(sections, this.restrictions(ast, renderer));
3335
3336
  }
3336
3337
  addSection(sections, content) {
@@ -3510,6 +3511,38 @@ var MarkdownInstructionFormatter = class extends BaseFormatter {
3510
3511
  const content = renderer.renderList(items);
3511
3512
  return renderer.renderSection("Diagrams", content) + "\n";
3512
3513
  }
3514
+ /**
3515
+ * Render remaining @knowledge text content that isn't consumed by other sections.
3516
+ * Strips "## Development Commands" and "## Post-Work Verification" sub-sections
3517
+ * since those are already rendered by commands() and postWork().
3518
+ */
3519
+ knowledgeContent(ast, _renderer) {
3520
+ const knowledge = this.findBlock(ast, "knowledge");
3521
+ if (!knowledge) return null;
3522
+ const text = this.extractText(knowledge.content);
3523
+ if (!text) return null;
3524
+ const consumedHeaders = ["## Development Commands", "## Post-Work Verification"];
3525
+ let remaining = text;
3526
+ for (const header of consumedHeaders) {
3527
+ const headerIndex = remaining.indexOf(header);
3528
+ if (headerIndex === -1) continue;
3529
+ const afterHeader = remaining.indexOf("\n", headerIndex);
3530
+ if (afterHeader === -1) {
3531
+ remaining = remaining.substring(0, headerIndex).trimEnd();
3532
+ continue;
3533
+ }
3534
+ const nextSection = remaining.indexOf("\n## ", afterHeader);
3535
+ if (nextSection === -1) {
3536
+ remaining = remaining.substring(0, headerIndex).trimEnd();
3537
+ } else {
3538
+ remaining = remaining.substring(0, headerIndex) + remaining.substring(nextSection + 1);
3539
+ }
3540
+ }
3541
+ remaining = remaining.trim();
3542
+ if (!remaining) return null;
3543
+ const normalizedContent = this.stripAllIndent(remaining);
3544
+ return normalizedContent + "\n";
3545
+ }
3513
3546
  restrictions(ast, renderer) {
3514
3547
  const block = this.findBlock(ast, "restrictions");
3515
3548
  if (!block) return null;
@@ -6427,7 +6460,7 @@ var FACTORY_VERSIONS = {
6427
6460
  },
6428
6461
  full: {
6429
6462
  name: "full",
6430
- description: "Multifile + additional skill supporting files",
6463
+ description: "Multifile + droids + additional supporting files",
6431
6464
  outputPath: "AGENTS.md"
6432
6465
  }
6433
6466
  };
@@ -6441,7 +6474,7 @@ var FactoryFormatter = class extends MarkdownInstructionFormatter {
6441
6474
  mainFileHeader: "# AGENTS.md",
6442
6475
  dotDir: ".factory",
6443
6476
  skillFileName: "SKILL.md",
6444
- hasAgents: false,
6477
+ hasAgents: true,
6445
6478
  hasCommands: true,
6446
6479
  hasSkills: true,
6447
6480
  skillsInMultifile: true,
@@ -6584,6 +6617,79 @@ var FactoryFormatter = class extends MarkdownInstructionFormatter {
6584
6617
  };
6585
6618
  }
6586
6619
  // ============================================================
6620
+ // Droid File Generation (Factory-specific)
6621
+ // ============================================================
6622
+ extractAgents(ast) {
6623
+ const agentsBlock = this.findBlock(ast, "agents");
6624
+ if (!agentsBlock) return [];
6625
+ const droids = [];
6626
+ const props = this.getProps(agentsBlock.content);
6627
+ for (const [name, value] of Object.entries(props)) {
6628
+ if (value && typeof value === "object" && !Array.isArray(value)) {
6629
+ const obj = value;
6630
+ const description = obj["description"] ? this.valueToString(obj["description"]) : "";
6631
+ if (!description) continue;
6632
+ droids.push({
6633
+ name: name.replace(/\./g, "-"),
6634
+ description,
6635
+ content: obj["content"] ? this.valueToString(obj["content"]) : "",
6636
+ model: obj["model"] ? this.valueToString(obj["model"]) : void 0,
6637
+ reasoningEffort: this.parseReasoningEffort(obj["reasoningEffort"]),
6638
+ tools: this.parseDroidTools(obj["tools"])
6639
+ });
6640
+ }
6641
+ }
6642
+ return droids;
6643
+ }
6644
+ generateAgentFile(config) {
6645
+ const droidConfig = config;
6646
+ const lines = [];
6647
+ lines.push("---");
6648
+ lines.push(`name: ${droidConfig.name}`);
6649
+ if (droidConfig.description) {
6650
+ lines.push(`description: ${this.yamlString(droidConfig.description)}`);
6651
+ }
6652
+ if (droidConfig.model) {
6653
+ lines.push(`model: ${droidConfig.model}`);
6654
+ }
6655
+ if (droidConfig.reasoningEffort) {
6656
+ lines.push(`reasoningEffort: ${droidConfig.reasoningEffort}`);
6657
+ }
6658
+ if (droidConfig.tools) {
6659
+ if (typeof droidConfig.tools === "string") {
6660
+ lines.push(`tools: ${droidConfig.tools}`);
6661
+ } else if (Array.isArray(droidConfig.tools) && droidConfig.tools.length > 0) {
6662
+ const toolsArray = droidConfig.tools.map((t) => `"${t}"`).join(", ");
6663
+ lines.push(`tools: [${toolsArray}]`);
6664
+ }
6665
+ }
6666
+ lines.push("---");
6667
+ lines.push("");
6668
+ if (droidConfig.content) {
6669
+ const dedentedContent = this.dedent(droidConfig.content);
6670
+ lines.push(dedentedContent);
6671
+ }
6672
+ return {
6673
+ path: `.factory/droids/${droidConfig.name}.md`,
6674
+ content: lines.join("\n") + "\n"
6675
+ };
6676
+ }
6677
+ parseReasoningEffort(value) {
6678
+ if (!value) return void 0;
6679
+ const str = this.valueToString(value);
6680
+ const valid = ["low", "medium", "high"];
6681
+ return valid.includes(str) ? str : void 0;
6682
+ }
6683
+ parseDroidTools(value) {
6684
+ if (!value) return void 0;
6685
+ if (typeof value === "string") return value;
6686
+ if (Array.isArray(value)) {
6687
+ const arr = value.map((v) => this.valueToString(v)).filter((s) => s.length > 0);
6688
+ return arr.length > 0 ? arr : void 0;
6689
+ }
6690
+ return this.valueToString(value);
6691
+ }
6692
+ // ============================================================
6587
6693
  // Handoff Extraction (Factory-specific)
6588
6694
  // ============================================================
6589
6695
  extractHandoffs(value) {
@@ -19200,16 +19306,170 @@ function parseSkillMd(content) {
19200
19306
  }
19201
19307
  var SKIP_FILES = /* @__PURE__ */ new Set([
19202
19308
  "SKILL.md",
19309
+ ".skillignore",
19203
19310
  ".DS_Store",
19204
19311
  "Thumbs.db",
19205
19312
  ".gitignore",
19206
19313
  ".gitkeep",
19207
19314
  ".npmrc",
19315
+ ".npmignore",
19208
19316
  ".env",
19209
19317
  ".env.local",
19210
- ".env.production"
19318
+ ".env.production",
19319
+ ".editorconfig",
19320
+ ".prettierrc",
19321
+ ".prettierrc.json",
19322
+ ".prettierrc.yaml",
19323
+ ".prettierrc.yml",
19324
+ ".prettierignore",
19325
+ ".eslintrc",
19326
+ ".eslintrc.js",
19327
+ ".eslintrc.cjs",
19328
+ ".eslintrc.json",
19329
+ ".eslintrc.yaml",
19330
+ ".eslintrc.yml",
19331
+ "eslint.config.js",
19332
+ "eslint.config.cjs",
19333
+ "eslint.config.mjs",
19334
+ "eslint.base.config.cjs",
19335
+ ".release-please-manifest.json",
19336
+ "release-please-config.json",
19337
+ "package-lock.json",
19338
+ "pnpm-lock.yaml",
19339
+ "pnpm-workspace.yaml",
19340
+ "yarn.lock",
19341
+ "tsconfig.json",
19342
+ "tsconfig.base.json",
19343
+ "tsconfig.build.json",
19344
+ "tsconfig.spec.json",
19345
+ "jest.config.ts",
19346
+ "jest.config.js",
19347
+ "vitest.config.ts",
19348
+ "vitest.config.js",
19349
+ "vite.config.ts",
19350
+ "vite.config.js",
19351
+ "nx.json",
19352
+ "project.json",
19353
+ "package.json",
19354
+ "Makefile",
19355
+ "Dockerfile",
19356
+ "docker-compose.yml",
19357
+ "docker-compose.yaml",
19358
+ ".dockerignore",
19359
+ "LICENSE",
19360
+ "LICENSE.md",
19361
+ "CHANGELOG.md",
19362
+ "CONTRIBUTING.md",
19363
+ "CODE_OF_CONDUCT.md",
19364
+ "ROADMAP.md"
19211
19365
  ]);
19212
- var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", "__pycache__", ".git", ".svn"]);
19366
+ var SKIP_DIRS = /* @__PURE__ */ new Set([
19367
+ "node_modules",
19368
+ "__pycache__",
19369
+ ".git",
19370
+ ".svn",
19371
+ ".github",
19372
+ ".husky",
19373
+ ".vscode",
19374
+ ".idea",
19375
+ ".verdaccio",
19376
+ ".nx",
19377
+ ".cache",
19378
+ ".turbo",
19379
+ "dist",
19380
+ "build",
19381
+ "out",
19382
+ "coverage",
19383
+ "tmp",
19384
+ ".tmp",
19385
+ "e2e",
19386
+ "__tests__",
19387
+ "__mocks__",
19388
+ "__fixtures__",
19389
+ "test",
19390
+ "tests",
19391
+ "spec",
19392
+ "fixtures"
19393
+ ]);
19394
+ function globToRegex(pattern) {
19395
+ const isDirPattern = pattern.endsWith("/");
19396
+ const cleanPattern = isDirPattern ? pattern.slice(0, -1) : pattern;
19397
+ const matchPath = cleanPattern.includes("/");
19398
+ let regexStr = "";
19399
+ let i = 0;
19400
+ while (i < cleanPattern.length) {
19401
+ const char = cleanPattern[i];
19402
+ if (char === "*") {
19403
+ if (cleanPattern[i + 1] === "*") {
19404
+ if (cleanPattern[i + 2] === "/") {
19405
+ regexStr += "(?:.+/)?";
19406
+ i += 3;
19407
+ } else {
19408
+ regexStr += ".*";
19409
+ i += 2;
19410
+ }
19411
+ } else {
19412
+ regexStr += "[^/]*";
19413
+ i++;
19414
+ }
19415
+ } else if (char === "?") {
19416
+ regexStr += "[^/]";
19417
+ i++;
19418
+ } else if (char === "[") {
19419
+ const closeIdx = cleanPattern.indexOf("]", i + 1);
19420
+ if (closeIdx > i) {
19421
+ regexStr += cleanPattern.slice(i, closeIdx + 1);
19422
+ i = closeIdx + 1;
19423
+ } else {
19424
+ regexStr += "\\[";
19425
+ i++;
19426
+ }
19427
+ } else if (".+^${}()|\\".includes(char)) {
19428
+ regexStr += "\\" + char;
19429
+ i++;
19430
+ } else {
19431
+ regexStr += char;
19432
+ i++;
19433
+ }
19434
+ }
19435
+ if (isDirPattern) {
19436
+ return { regex: new RegExp(`^${regexStr}(?:/|$)`), matchPath: true };
19437
+ }
19438
+ return { regex: new RegExp(`^${regexStr}$`), matchPath };
19439
+ }
19440
+ function parseSkillIgnore(content) {
19441
+ const patterns = [];
19442
+ for (const rawLine of content.split("\n")) {
19443
+ const line = rawLine.trim();
19444
+ if (!line || line.startsWith("#")) continue;
19445
+ const negated = line.startsWith("!");
19446
+ const pattern = negated ? line.slice(1) : line;
19447
+ if (!pattern) continue;
19448
+ const { regex, matchPath } = globToRegex(pattern);
19449
+ patterns.push({ regex, matchPath, negated });
19450
+ }
19451
+ return { patterns };
19452
+ }
19453
+ function isIgnoredByRules(relPath, rules) {
19454
+ const basename3 = relPath.split("/").pop() ?? relPath;
19455
+ let ignored = false;
19456
+ for (const { regex, matchPath, negated } of rules.patterns) {
19457
+ const target = matchPath ? relPath : basename3;
19458
+ if (regex.test(target)) {
19459
+ ignored = !negated;
19460
+ }
19461
+ }
19462
+ return ignored;
19463
+ }
19464
+ async function loadSkillIgnore(skillDir) {
19465
+ const ignorePath = resolve4(skillDir, ".skillignore");
19466
+ try {
19467
+ const content = await readFile6(ignorePath, "utf-8");
19468
+ return parseSkillIgnore(content);
19469
+ } catch {
19470
+ return null;
19471
+ }
19472
+ }
19213
19473
  var MAX_RESOURCE_SIZE = 1048576;
19214
19474
  var MAX_TOTAL_RESOURCE_SIZE = 10485760;
19215
19475
  var MAX_RESOURCE_COUNT = 100;
@@ -19229,6 +19489,7 @@ var noopLogger2 = {
19229
19489
  }
19230
19490
  };
19231
19491
  async function discoverSkillResources(skillDir, logger = noopLogger2) {
19492
+ const ignoreRules = await loadSkillIgnore(skillDir);
19232
19493
  const entries = await readdir2(skillDir, { recursive: true, withFileTypes: true });
19233
19494
  const resources = [];
19234
19495
  let totalSize = 0;
@@ -19246,8 +19507,13 @@ async function discoverSkillResources(skillDir, logger = noopLogger2) {
19246
19507
  if (SKIP_FILES.has(entry.name)) continue;
19247
19508
  const fullPath = resolve4(entry.parentPath, entry.name);
19248
19509
  const relPath = relative(skillDir, fullPath);
19510
+ const relPathNormalized = relPath.split(sep2).join("/");
19249
19511
  const pathSegments = relPath.split(sep2);
19250
19512
  if (pathSegments.some((s) => SKIP_DIRS.has(s))) continue;
19513
+ if (ignoreRules && isIgnoredByRules(relPathNormalized, ignoreRules)) {
19514
+ logger.debug(`Skipping resource ignored by .skillignore: ${relPath}`);
19515
+ continue;
19516
+ }
19251
19517
  if (!isSafeRelativePath(relPath)) {
19252
19518
  logger.verbose(`Skipping resource with unsafe path: ${relPath}`);
19253
19519
  continue;
@@ -20771,12 +21037,13 @@ function extractGuardReferences(content) {
20771
21037
  }
20772
21038
 
20773
21039
  // packages/validator/src/walker.ts
20774
- function walkText(ast, callback) {
21040
+ function walkText(ast, callback, options) {
21041
+ const exclude = options?.excludeProperties ? new Set(options.excludeProperties) : void 0;
20775
21042
  for (const block of ast.blocks) {
20776
- walkBlockContent(block.content, block.loc, callback);
21043
+ walkBlockContent(block.content, block.loc, callback, exclude);
20777
21044
  }
20778
21045
  for (const ext of ast.extends) {
20779
- walkBlockContent(ext.content, ext.loc, callback);
21046
+ walkBlockContent(ext.content, ext.loc, callback, exclude);
20780
21047
  }
20781
21048
  }
20782
21049
  function walkBlocks(ast, callback) {
@@ -20792,40 +21059,41 @@ function walkUses(ast, callback) {
20792
21059
  callback(use);
20793
21060
  }
20794
21061
  }
20795
- function walkBlockContent(content, fallbackLoc, callback) {
21062
+ function walkBlockContent(content, fallbackLoc, callback, exclude) {
20796
21063
  switch (content.type) {
20797
21064
  case "TextContent":
20798
21065
  callback(content.value, content.loc ?? fallbackLoc);
20799
21066
  break;
20800
21067
  case "ObjectContent":
20801
- walkObjectProperties(content.properties, content.loc ?? fallbackLoc, callback);
21068
+ walkObjectProperties(content.properties, content.loc ?? fallbackLoc, callback, exclude);
20802
21069
  break;
20803
21070
  case "ArrayContent":
20804
- walkArrayElements(content.elements, content.loc ?? fallbackLoc, callback);
21071
+ walkArrayElements(content.elements, content.loc ?? fallbackLoc, callback, exclude);
20805
21072
  break;
20806
21073
  case "MixedContent":
20807
21074
  if (content.text) {
20808
21075
  callback(content.text.value, content.text.loc ?? fallbackLoc);
20809
21076
  }
20810
- walkObjectProperties(content.properties, content.loc ?? fallbackLoc, callback);
21077
+ walkObjectProperties(content.properties, content.loc ?? fallbackLoc, callback, exclude);
20811
21078
  break;
20812
21079
  }
20813
21080
  }
20814
- function walkObjectProperties(properties, loc, callback) {
20815
- for (const value of Object.values(properties)) {
20816
- walkValue(value, loc, callback);
21081
+ function walkObjectProperties(properties, loc, callback, exclude) {
21082
+ for (const [key, value] of Object.entries(properties)) {
21083
+ if (exclude?.has(key)) continue;
21084
+ walkValue(value, loc, callback, exclude);
20817
21085
  }
20818
21086
  }
20819
- function walkArrayElements(elements, loc, callback) {
21087
+ function walkArrayElements(elements, loc, callback, exclude) {
20820
21088
  for (const element of elements) {
20821
- walkValue(element, loc, callback);
21089
+ walkValue(element, loc, callback, exclude);
20822
21090
  }
20823
21091
  }
20824
- function walkValue(value, loc, callback) {
21092
+ function walkValue(value, loc, callback, exclude) {
20825
21093
  if (typeof value === "string") {
20826
21094
  callback(value, loc);
20827
21095
  } else if (Array.isArray(value)) {
20828
- walkArrayElements(value, loc, callback);
21096
+ walkArrayElements(value, loc, callback, exclude);
20829
21097
  } else if (value !== null && typeof value === "object") {
20830
21098
  if ("type" in value) {
20831
21099
  const typed = value;
@@ -20833,10 +21101,28 @@ function walkValue(value, loc, callback) {
20833
21101
  callback(typed.value, typed.loc ?? loc);
20834
21102
  }
20835
21103
  } else {
20836
- walkObjectProperties(value, loc, callback);
21104
+ walkObjectProperties(value, loc, callback, exclude);
20837
21105
  }
20838
21106
  }
20839
21107
  }
21108
+ function offsetLocation(baseLoc, text, charIndex) {
21109
+ let line = baseLoc.line;
21110
+ let column = baseLoc.column;
21111
+ for (let i = 0; i < charIndex && i < text.length; i++) {
21112
+ if (text[i] === "\n") {
21113
+ line++;
21114
+ column = 1;
21115
+ } else {
21116
+ column++;
21117
+ }
21118
+ }
21119
+ return {
21120
+ file: baseLoc.file,
21121
+ line,
21122
+ column,
21123
+ offset: baseLoc.offset !== void 0 ? baseLoc.offset + charIndex : void 0
21124
+ };
21125
+ }
20840
21126
  function hasContent(content) {
20841
21127
  switch (content.type) {
20842
21128
  case "TextContent":
@@ -21225,6 +21511,12 @@ var BLOCKED_PATTERNS_ALL_LANGUAGES = [
21225
21511
  ...BLOCKED_PATTERNS_RO,
21226
21512
  ...BLOCKED_PATTERNS_HE
21227
21513
  ];
21514
+ var NEGATION_PREFIX = /(?:prevent|avoid|block|detect|flag|report|stop|prohibit|anti[- ]|against|don['']?t|do\s+not|never|must\s+not|should\s+not|cannot|warning.*about|protection\s+(?:from|against))\s+/i;
21515
+ function isNegatedMatch(text, matchIndex) {
21516
+ const lookbackStart = Math.max(0, matchIndex - 60);
21517
+ const prefix = text.slice(lookbackStart, matchIndex);
21518
+ return NEGATION_PREFIX.test(prefix);
21519
+ }
21228
21520
  var blockedPatterns = {
21229
21521
  id: "PS005",
21230
21522
  name: "blocked-patterns",
@@ -21237,17 +21529,30 @@ var blockedPatterns = {
21237
21529
  (p) => typeof p === "string" ? new RegExp(p, "i") : p
21238
21530
  )
21239
21531
  ];
21240
- walkText(ctx.ast, (text, loc) => {
21241
- for (const pattern of patterns) {
21242
- if (pattern.test(text)) {
21243
- ctx.report({
21244
- message: `Blocked pattern detected: ${pattern.source}`,
21245
- location: loc,
21246
- suggestion: "Remove or rephrase the flagged content"
21247
- });
21532
+ walkText(
21533
+ ctx.ast,
21534
+ (text, loc) => {
21535
+ for (const pattern of patterns) {
21536
+ const globalPattern = new RegExp(
21537
+ pattern.source,
21538
+ pattern.flags.includes("g") ? pattern.flags : pattern.flags + "g"
21539
+ );
21540
+ let match;
21541
+ while ((match = globalPattern.exec(text)) !== null) {
21542
+ if (isNegatedMatch(text, match.index)) {
21543
+ continue;
21544
+ }
21545
+ ctx.report({
21546
+ message: `Blocked pattern detected: ${pattern.source}`,
21547
+ location: offsetLocation(loc, text, match.index),
21548
+ suggestion: "Remove or rephrase the flagged content"
21549
+ });
21550
+ break;
21551
+ }
21248
21552
  }
21249
- }
21250
- });
21553
+ },
21554
+ { excludeProperties: ["resources"] }
21555
+ );
21251
21556
  }
21252
21557
  };
21253
21558
 
@@ -21640,87 +21945,91 @@ var suspiciousUrls = {
21640
21945
  description: "Detect suspicious URLs (HTTP, shorteners, credential parameters, IDN homograph attacks)",
21641
21946
  defaultSeverity: "warning",
21642
21947
  validate: (ctx) => {
21643
- walkText(ctx.ast, (text, loc) => {
21644
- const httpMatches = text.match(HTTP_URL_PATTERN);
21645
- if (httpMatches) {
21646
- for (const match of httpMatches) {
21647
- ctx.report({
21648
- message: `Insecure HTTP URL detected: ${match}`,
21649
- location: loc,
21650
- suggestion: "Use HTTPS instead of HTTP for secure communication"
21651
- });
21652
- }
21653
- }
21654
- for (const pattern of URL_SHORTENER_PATTERNS) {
21655
- pattern.lastIndex = 0;
21656
- const shortenerMatches = text.match(pattern);
21657
- if (shortenerMatches) {
21658
- for (const match of shortenerMatches) {
21948
+ walkText(
21949
+ ctx.ast,
21950
+ (text, loc) => {
21951
+ const httpMatches = text.match(HTTP_URL_PATTERN);
21952
+ if (httpMatches) {
21953
+ for (const match of httpMatches) {
21659
21954
  ctx.report({
21660
- message: `URL shortener detected: ${match}`,
21955
+ message: `Insecure HTTP URL detected: ${match}`,
21661
21956
  location: loc,
21662
- suggestion: "Use full URLs instead of shorteners to ensure destination transparency"
21957
+ suggestion: "Use HTTPS instead of HTTP for secure communication"
21663
21958
  });
21664
21959
  }
21665
21960
  }
21666
- }
21667
- const paramMatches = text.match(SUSPICIOUS_PARAM_PATTERN);
21668
- if (paramMatches) {
21669
- for (const match of paramMatches) {
21670
- ctx.report({
21671
- message: `URL with suspicious credential parameter detected: ${match}`,
21672
- location: loc,
21673
- suggestion: "Avoid embedding credentials or tokens in URLs"
21674
- });
21675
- }
21676
- }
21677
- PUNYCODE_URL_PATTERN.lastIndex = 0;
21678
- const punycodeMatches = text.match(PUNYCODE_URL_PATTERN);
21679
- if (punycodeMatches) {
21680
- for (const match of punycodeMatches) {
21681
- const domain = extractDomain(match);
21682
- if (domain) {
21683
- const impersonatedService = detectImpersonatedService(domain);
21684
- if (impersonatedService) {
21961
+ for (const pattern of URL_SHORTENER_PATTERNS) {
21962
+ pattern.lastIndex = 0;
21963
+ const shortenerMatches = text.match(pattern);
21964
+ if (shortenerMatches) {
21965
+ for (const match of shortenerMatches) {
21685
21966
  ctx.report({
21686
- message: `Potential IDN homograph attack detected: ${match} may be impersonating "${impersonatedService}"`,
21967
+ message: `URL shortener detected: ${match}`,
21687
21968
  location: loc,
21688
- suggestion: "Punycode domains (xn--) can visually impersonate legitimate sites. Verify the actual domain carefully."
21689
- });
21690
- } else {
21691
- ctx.report({
21692
- message: `Punycode domain detected: ${match}`,
21693
- location: loc,
21694
- suggestion: "Punycode domains (xn--) can be legitimate international domains, but may also be used for homograph attacks. Verify the domain is intentional."
21969
+ suggestion: "Use full URLs instead of shorteners to ensure destination transparency"
21695
21970
  });
21696
21971
  }
21697
21972
  }
21698
21973
  }
21699
- }
21700
- ALL_URLS_PATTERN.lastIndex = 0;
21701
- const allUrls = text.match(ALL_URLS_PATTERN);
21702
- if (allUrls) {
21703
- for (const url of allUrls) {
21704
- const domain = extractDomain(url);
21705
- if (domain) {
21706
- const { isAttack, impersonatedService, mixedScripts } = checkHomographAttack(domain);
21707
- if (isAttack && impersonatedService) {
21708
- ctx.report({
21709
- message: `IDN homograph attack detected: "${domain}" uses deceptive characters to impersonate "${impersonatedService}"`,
21710
- location: loc,
21711
- suggestion: `This domain uses ${mixedScripts ? `mixed scripts (${mixedScripts.join("+")})` : "homoglyph characters"} to visually mimic a legitimate service. Do not trust this URL.`
21712
- });
21713
- } else if (mixedScripts && mixedScripts.length > 1) {
21714
- ctx.report({
21715
- message: `Mixed script domain detected: "${domain}" uses ${mixedScripts.join(" + ")} characters`,
21716
- location: loc,
21717
- suggestion: "Domains mixing different character scripts (e.g., Latin + Cyrillic) may be attempts to deceive users. Verify this is intentional."
21718
- });
21974
+ const paramMatches = text.match(SUSPICIOUS_PARAM_PATTERN);
21975
+ if (paramMatches) {
21976
+ for (const match of paramMatches) {
21977
+ ctx.report({
21978
+ message: `URL with suspicious credential parameter detected: ${match}`,
21979
+ location: loc,
21980
+ suggestion: "Avoid embedding credentials or tokens in URLs"
21981
+ });
21982
+ }
21983
+ }
21984
+ PUNYCODE_URL_PATTERN.lastIndex = 0;
21985
+ const punycodeMatches = text.match(PUNYCODE_URL_PATTERN);
21986
+ if (punycodeMatches) {
21987
+ for (const match of punycodeMatches) {
21988
+ const domain = extractDomain(match);
21989
+ if (domain) {
21990
+ const impersonatedService = detectImpersonatedService(domain);
21991
+ if (impersonatedService) {
21992
+ ctx.report({
21993
+ message: `Potential IDN homograph attack detected: ${match} may be impersonating "${impersonatedService}"`,
21994
+ location: loc,
21995
+ suggestion: "Punycode domains (xn--) can visually impersonate legitimate sites. Verify the actual domain carefully."
21996
+ });
21997
+ } else {
21998
+ ctx.report({
21999
+ message: `Punycode domain detected: ${match}`,
22000
+ location: loc,
22001
+ suggestion: "Punycode domains (xn--) can be legitimate international domains, but may also be used for homograph attacks. Verify the domain is intentional."
22002
+ });
22003
+ }
21719
22004
  }
21720
22005
  }
21721
22006
  }
21722
- }
21723
- });
22007
+ ALL_URLS_PATTERN.lastIndex = 0;
22008
+ const allUrls = text.match(ALL_URLS_PATTERN);
22009
+ if (allUrls) {
22010
+ for (const url of allUrls) {
22011
+ const domain = extractDomain(url);
22012
+ if (domain) {
22013
+ const { isAttack, impersonatedService, mixedScripts } = checkHomographAttack(domain);
22014
+ if (isAttack && impersonatedService) {
22015
+ ctx.report({
22016
+ message: `IDN homograph attack detected: "${domain}" uses deceptive characters to impersonate "${impersonatedService}"`,
22017
+ location: loc,
22018
+ suggestion: `This domain uses ${mixedScripts ? `mixed scripts (${mixedScripts.join("+")})` : "homoglyph characters"} to visually mimic a legitimate service. Do not trust this URL.`
22019
+ });
22020
+ } else if (mixedScripts && mixedScripts.length > 1) {
22021
+ ctx.report({
22022
+ message: `Mixed script domain detected: "${domain}" uses ${mixedScripts.join(" + ")} characters`,
22023
+ location: loc,
22024
+ suggestion: "Domains mixing different character scripts (e.g., Latin + Cyrillic) may be attempts to deceive users. Verify this is intentional."
22025
+ });
22026
+ }
22027
+ }
22028
+ }
22029
+ }
22030
+ },
22031
+ { excludeProperties: ["resources"] }
22032
+ );
21724
22033
  }
21725
22034
  };
21726
22035
 
@@ -21760,17 +22069,21 @@ var authorityInjection = {
21760
22069
  description: "Detect authoritative override phrases that may indicate prompt injection",
21761
22070
  defaultSeverity: "error",
21762
22071
  validate: (ctx) => {
21763
- walkText(ctx.ast, (text, loc) => {
21764
- for (const pattern of AUTHORITY_PATTERNS) {
21765
- if (pattern.test(text)) {
21766
- ctx.report({
21767
- message: `Authority injection pattern detected: ${pattern.source}`,
21768
- location: loc,
21769
- suggestion: "Remove authoritative override language that could be used for prompt injection"
21770
- });
22072
+ walkText(
22073
+ ctx.ast,
22074
+ (text, loc) => {
22075
+ for (const pattern of AUTHORITY_PATTERNS) {
22076
+ if (pattern.test(text)) {
22077
+ ctx.report({
22078
+ message: `Authority injection pattern detected: ${pattern.source}`,
22079
+ location: loc,
22080
+ suggestion: "Remove authoritative override language that could be used for prompt injection"
22081
+ });
22082
+ }
21771
22083
  }
21772
- }
21773
- });
22084
+ },
22085
+ { excludeProperties: ["resources"] }
22086
+ );
21774
22087
  }
21775
22088
  };
21776
22089
 
@@ -22156,26 +22469,30 @@ var obfuscatedContent = {
22156
22469
  description: "Detect obfuscated content using sanitization pipeline (decode and check all encodings)",
22157
22470
  defaultSeverity: "warning",
22158
22471
  validate: (ctx) => {
22159
- walkText(ctx.ast, (text, loc) => {
22160
- const encodedMatches = detectAndDecodeEncodings(text);
22161
- for (const match of encodedMatches) {
22162
- ctx.report({
22163
- message: `Malicious content detected in ${match.type}: ${match.issues.join(", ")}. Decoded: "${match.decoded.substring(0, 50)}${match.decoded.length > 50 ? "..." : ""}"`,
22164
- location: loc,
22165
- suggestion: "Encoded content is automatically decoded and checked for security patterns. Remove the malicious payload or use plain text."
22166
- });
22167
- }
22168
- const hasLongBase64 = (text.match(BASE64_PATTERN) || []).some(
22169
- (m) => m.length >= MIN_ENCODED_LENGTH * 2 && !isLikelyLegitimateBase64(text, m)
22170
- );
22171
- if (hasLongBase64 && encodedMatches.length === 0) {
22172
- ctx.report({
22173
- message: "Long Base64-encoded content detected that may hide payloads",
22174
- location: loc,
22175
- suggestion: "If this is intentional, consider using plain text or documenting the purpose"
22176
- });
22177
- }
22178
- });
22472
+ walkText(
22473
+ ctx.ast,
22474
+ (text, loc) => {
22475
+ const encodedMatches = detectAndDecodeEncodings(text);
22476
+ for (const match of encodedMatches) {
22477
+ ctx.report({
22478
+ message: `Malicious content detected in ${match.type}: ${match.issues.join(", ")}. Decoded: "${match.decoded.substring(0, 50)}${match.decoded.length > 50 ? "..." : ""}"`,
22479
+ location: loc,
22480
+ suggestion: "Encoded content is automatically decoded and checked for security patterns. Remove the malicious payload or use plain text."
22481
+ });
22482
+ }
22483
+ const hasLongBase64 = (text.match(BASE64_PATTERN) || []).some(
22484
+ (m) => m.length >= MIN_ENCODED_LENGTH * 2 && !isLikelyLegitimateBase64(text, m)
22485
+ );
22486
+ if (hasLongBase64 && encodedMatches.length === 0) {
22487
+ ctx.report({
22488
+ message: "Long Base64-encoded content detected that may hide payloads",
22489
+ location: loc,
22490
+ suggestion: "If this is intentional, consider using plain text or documenting the purpose"
22491
+ });
22492
+ }
22493
+ },
22494
+ { excludeProperties: ["resources"] }
22495
+ );
22179
22496
  }
22180
22497
  };
22181
22498
 
@@ -22292,22 +22609,32 @@ var GREEK_LOOKALIKES = /* @__PURE__ */ new Map([
22292
22609
  ["\u0396", "\u0396 (Greek) looks like Z (Latin)"]
22293
22610
  ]);
22294
22611
  var EXCESSIVE_COMBINING_PATTERN = /[\u0300-\u036F\u0483-\u0489\u0591-\u05BD\u064B-\u065F]{4,}/;
22295
- var LATIN_PATTERN = /[a-zA-Z]/;
22612
+ var LATIN_CHAR = /[a-zA-Z]/;
22613
+ var CYRILLIC_CHAR = /[\u0400-\u04FF]/;
22614
+ var GREEK_CHAR = /[\u0370-\u03FF]/;
22615
+ var WORD_PATTERN = /[a-zA-Z\u0370-\u03FF\u0400-\u04FF]+/g;
22296
22616
  function findHomographAttacks(text) {
22297
22617
  const results = [];
22298
- const hasLatin = LATIN_PATTERN.test(text);
22299
- if (!hasLatin) {
22300
- return results;
22301
- }
22302
- for (let i = 0; i < text.length; i++) {
22303
- const char = text[i];
22304
- const cyrillicDesc = CYRILLIC_LOOKALIKES.get(char);
22305
- if (cyrillicDesc) {
22306
- results.push({ char, description: cyrillicDesc, index: i });
22307
- }
22308
- const greekDesc = GREEK_LOOKALIKES.get(char);
22309
- if (greekDesc) {
22310
- results.push({ char, description: greekDesc, index: i });
22618
+ let wordMatch;
22619
+ const wordPattern = new RegExp(WORD_PATTERN.source, WORD_PATTERN.flags);
22620
+ while ((wordMatch = wordPattern.exec(text)) !== null) {
22621
+ const word = wordMatch[0];
22622
+ const wordStart = wordMatch.index;
22623
+ const hasLatin = LATIN_CHAR.test(word);
22624
+ const hasCyrillic = CYRILLIC_CHAR.test(word);
22625
+ const hasGreek = GREEK_CHAR.test(word);
22626
+ if (!hasLatin) continue;
22627
+ if (!hasCyrillic && !hasGreek) continue;
22628
+ for (let i = 0; i < word.length; i++) {
22629
+ const char = word[i];
22630
+ const cyrillicDesc = CYRILLIC_LOOKALIKES.get(char);
22631
+ if (cyrillicDesc) {
22632
+ results.push({ char, description: cyrillicDesc, index: wordStart + i });
22633
+ }
22634
+ const greekDesc = GREEK_LOOKALIKES.get(char);
22635
+ if (greekDesc) {
22636
+ results.push({ char, description: greekDesc, index: wordStart + i });
22637
+ }
22311
22638
  }
22312
22639
  }
22313
22640
  return results;
@@ -22340,47 +22667,51 @@ var unicodeSecurity = {
22340
22667
  description: "Detect Unicode-based attacks (bidi overrides, zero-width, homoglyphs)",
22341
22668
  defaultSeverity: "error",
22342
22669
  validate: (ctx) => {
22343
- walkText(ctx.ast, (text, loc) => {
22344
- const bidiChars = findBidiChars(text);
22345
- if (bidiChars.length > 0) {
22346
- const descriptions = bidiChars.slice(0, 3).map((b) => b.description).join(", ");
22347
- const suffix = bidiChars.length > 3 ? ` and ${bidiChars.length - 3} more` : "";
22348
- ctx.report({
22349
- message: `Bidirectional text override detected: ${descriptions}${suffix}`,
22350
- location: loc,
22351
- suggestion: "Remove bidirectional override characters that may hide malicious content"
22352
- });
22353
- }
22354
- const zeroWidthChars = findZeroWidthChars(text);
22355
- if (zeroWidthChars.length > 0) {
22356
- const descriptions = zeroWidthChars.slice(0, 3).map((z) => z.description).join(", ");
22357
- const suffix = zeroWidthChars.length > 3 ? ` and ${zeroWidthChars.length - 3} more` : "";
22358
- ctx.report({
22359
- message: `Zero-width characters detected: ${descriptions}${suffix}`,
22360
- location: loc,
22361
- suggestion: "Remove zero-width characters that may be used to evade pattern matching"
22362
- });
22363
- }
22364
- const homographs = findHomographAttacks(text);
22365
- if (homographs.length > 0) {
22366
- const descriptions = homographs.slice(0, 3).map((h) => h.description).join(", ");
22367
- const suffix = homographs.length > 3 ? ` and ${homographs.length - 3} more` : "";
22368
- ctx.report({
22369
- message: `Potential homograph attack: ${descriptions}${suffix}`,
22370
- location: loc,
22371
- suggestion: "Replace lookalike Cyrillic/Greek characters with Latin equivalents"
22372
- });
22373
- }
22374
- if (EXCESSIVE_COMBINING_PATTERN.test(text)) {
22375
- const match = text.match(EXCESSIVE_COMBINING_PATTERN);
22376
- const charCodes = match ? Array.from(match[0]).slice(0, 4).map((c) => `U+${c.charCodeAt(0).toString(16).toUpperCase().padStart(4, "0")}`).join(", ") : "unknown";
22377
- ctx.report({
22378
- message: `Excessive combining characters (Zalgo text) detected: ${charCodes}...`,
22379
- location: loc,
22380
- suggestion: "Remove excessive diacritical marks that may be used to obscure content"
22381
- });
22382
- }
22383
- });
22670
+ walkText(
22671
+ ctx.ast,
22672
+ (text, loc) => {
22673
+ const bidiChars = findBidiChars(text);
22674
+ if (bidiChars.length > 0) {
22675
+ const descriptions = bidiChars.slice(0, 3).map((b) => b.description).join(", ");
22676
+ const suffix = bidiChars.length > 3 ? ` and ${bidiChars.length - 3} more` : "";
22677
+ ctx.report({
22678
+ message: `Bidirectional text override detected: ${descriptions}${suffix}`,
22679
+ location: offsetLocation(loc, text, bidiChars[0].index),
22680
+ suggestion: "Remove bidirectional override characters that may hide malicious content"
22681
+ });
22682
+ }
22683
+ const zeroWidthChars = findZeroWidthChars(text);
22684
+ if (zeroWidthChars.length > 0) {
22685
+ const descriptions = zeroWidthChars.slice(0, 3).map((z) => z.description).join(", ");
22686
+ const suffix = zeroWidthChars.length > 3 ? ` and ${zeroWidthChars.length - 3} more` : "";
22687
+ ctx.report({
22688
+ message: `Zero-width characters detected: ${descriptions}${suffix}`,
22689
+ location: offsetLocation(loc, text, zeroWidthChars[0].index),
22690
+ suggestion: "Remove zero-width characters that may be used to evade pattern matching"
22691
+ });
22692
+ }
22693
+ const homographs = findHomographAttacks(text);
22694
+ if (homographs.length > 0) {
22695
+ const descriptions = homographs.slice(0, 3).map((h) => h.description).join(", ");
22696
+ const suffix = homographs.length > 3 ? ` and ${homographs.length - 3} more` : "";
22697
+ ctx.report({
22698
+ message: `Potential homograph attack: ${descriptions}${suffix}`,
22699
+ location: offsetLocation(loc, text, homographs[0].index),
22700
+ suggestion: "Replace lookalike Cyrillic/Greek characters with Latin equivalents"
22701
+ });
22702
+ }
22703
+ const combiningMatch = EXCESSIVE_COMBINING_PATTERN.exec(text);
22704
+ if (combiningMatch) {
22705
+ const charCodes = Array.from(combiningMatch[0]).slice(0, 4).map((c) => `U+${c.charCodeAt(0).toString(16).toUpperCase().padStart(4, "0")}`).join(", ");
22706
+ ctx.report({
22707
+ message: `Excessive combining characters (Zalgo text) detected: ${charCodes}...`,
22708
+ location: offsetLocation(loc, text, combiningMatch.index),
22709
+ suggestion: "Remove excessive diacritical marks that may be used to obscure content"
22710
+ });
22711
+ }
22712
+ },
22713
+ { excludeProperties: ["resources"] }
22714
+ );
22384
22715
  }
22385
22716
  };
22386
22717
 
@@ -23181,8 +23512,14 @@ async function writeOutputs(outputs, options, _config, services) {
23181
23512
  result.written.push(outputPath);
23182
23513
  }
23183
23514
  } else {
23184
- ConsoleOutput.warning(`Would conflict: ${outputPath} (not generated by PromptScript)`);
23185
- result.written.push(outputPath);
23515
+ const existingContent = await readFile7(outputPath, "utf-8");
23516
+ if (existingContent === output.content) {
23517
+ ConsoleOutput.dryRun(`Unchanged: ${outputPath}`);
23518
+ result.unchanged.push(outputPath);
23519
+ } else {
23520
+ ConsoleOutput.warning(`Would conflict: ${outputPath} (not generated by PromptScript)`);
23521
+ result.written.push(outputPath);
23522
+ }
23186
23523
  }
23187
23524
  } else {
23188
23525
  ConsoleOutput.dryRun(`Would write: ${outputPath}`);
@@ -23213,6 +23550,17 @@ async function writeOutputs(outputs, options, _config, services) {
23213
23550
  result.written.push(outputPath);
23214
23551
  continue;
23215
23552
  }
23553
+ let contentMatches = false;
23554
+ try {
23555
+ const existingContent = await readFile7(outputPath, "utf-8");
23556
+ contentMatches = existingContent === output.content;
23557
+ } catch {
23558
+ }
23559
+ if (contentMatches) {
23560
+ ConsoleOutput.unchanged(outputPath);
23561
+ result.unchanged.push(outputPath);
23562
+ continue;
23563
+ }
23216
23564
  if (options.force || overwriteAll) {
23217
23565
  await mkdir2(dirname6(outputPath), { recursive: true });
23218
23566
  await writeFile2(outputPath, output.content, "utf-8");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@promptscript/cli",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "CLI for PromptScript - standardize AI instructions across GitHub Copilot, Claude, Cursor and other AI tools",
5
5
  "keywords": [
6
6
  "cli",
@@ -215,7 +215,8 @@ userInvocable, allowedTools, context ("fork" or "inherit"), agent.
215
215
 
216
216
  ### @agents
217
217
 
218
- Custom subagent definitions:
218
+ Custom subagent definitions. Compiles to `.claude/agents/` for Claude Code,
219
+ `.github/agents/` for GitHub Copilot, `.factory/droids/` for Factory AI, etc.
219
220
 
220
221
  ```
221
222
  @agents {
@@ -229,6 +230,10 @@ Custom subagent definitions:
229
230
  }
230
231
  ```
231
232
 
233
+ Factory AI droids support additional properties: `model` (any model ID or "inherit"),
234
+ `reasoningEffort` ("low", "medium", "high"), and `tools` (category name like "read-only"
235
+ or array of tool IDs).
236
+
232
237
  ### @knowledge
233
238
 
234
239
  Reference documentation as triple-quoted text. Used for command references,
@@ -331,21 +336,21 @@ prs diff --target claude # Show compilation diff
331
336
 
332
337
  38 supported targets. Key examples:
333
338
 
334
- | Target | Main File | Skills |
335
- | ----------- | ------------------------------- | ------------------------------ |
336
- | GitHub | .github/copilot-instructions.md | .github/skills/\*/SKILL.md |
337
- | Claude | CLAUDE.md | .claude/skills/\*/SKILL.md |
338
- | Cursor | .cursor/rules/project.mdc | .cursor/commands/\*.md |
339
- | Antigravity | .agent/rules/project.md | .agent/rules/\*.md |
340
- | Factory | AGENTS.md | .factory/skills/\*/SKILL.md |
341
- | OpenCode | OPENCODE.md | .opencode/skills/\*/SKILL.md |
342
- | Gemini | GEMINI.md | .gemini/skills/\*/skill.md |
343
- | Windsurf | .windsurf/rules/project.md | .windsurf/skills/\*/SKILL.md |
344
- | Cline | .clinerules | .agents/skills/\*/SKILL.md |
345
- | Roo Code | .roorules | .roo/skills/\*/SKILL.md |
346
- | Codex | AGENTS.md | .agents/skills/\*/SKILL.md |
347
- | Continue | .continue/rules/project.md | .continue/skills/\*/SKILL.md |
348
- | + 26 more | | See full list in documentation |
339
+ | Target | Main File | Skills |
340
+ | ----------- | ------------------------------- | -------------------------------------------------- |
341
+ | GitHub | .github/copilot-instructions.md | .github/skills/\*/SKILL.md |
342
+ | Claude | CLAUDE.md | .claude/skills/\*/SKILL.md |
343
+ | Cursor | .cursor/rules/project.mdc | .cursor/commands/\*.md |
344
+ | Antigravity | .agent/rules/project.md | .agent/rules/\*.md |
345
+ | Factory | AGENTS.md | .factory/skills/\*/SKILL.md, .factory/droids/\*.md |
346
+ | OpenCode | OPENCODE.md | .opencode/skills/\*/SKILL.md |
347
+ | Gemini | GEMINI.md | .gemini/skills/\*/skill.md |
348
+ | Windsurf | .windsurf/rules/project.md | .windsurf/skills/\*/SKILL.md |
349
+ | Cline | .clinerules | .agents/skills/\*/SKILL.md |
350
+ | Roo Code | .roorules | .roo/skills/\*/SKILL.md |
351
+ | Codex | AGENTS.md | .agents/skills/\*/SKILL.md |
352
+ | Continue | .continue/rules/project.md | .continue/skills/\*/SKILL.md |
353
+ | + 26 more | | See full list in documentation |
349
354
 
350
355
  ## Project Organization
351
356
 
@@ -1 +1 @@
1
- {"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../../../../packages/cli/src/commands/compile.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAQlD,OAAO,EAAE,KAAK,WAAW,EAAyB,MAAM,gBAAgB,CAAC;AAwTzE;;GAEG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,cAAc,EACvB,QAAQ,GAAE,WAAqC,GAC9C,OAAO,CAAC,IAAI,CAAC,CA8Gf"}
1
+ {"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../../../../packages/cli/src/commands/compile.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAQlD,OAAO,EAAE,KAAK,WAAW,EAAyB,MAAM,gBAAgB,CAAC;AAgVzE;;GAEG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,cAAc,EACvB,QAAQ,GAAE,WAAqC,GAC9C,OAAO,CAAC,IAAI,CAAC,CA8Gf"}