veto-leash 0.1.3 → 1.0.1

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 (96) hide show
  1. package/README.md +111 -196
  2. package/dist/ast/builtins.d.ts +28 -0
  3. package/dist/ast/builtins.d.ts.map +1 -0
  4. package/dist/ast/builtins.js +361 -0
  5. package/dist/ast/builtins.js.map +1 -0
  6. package/dist/ast/checker.d.ts +17 -0
  7. package/dist/ast/checker.d.ts.map +1 -0
  8. package/dist/ast/checker.js +97 -0
  9. package/dist/ast/checker.js.map +1 -0
  10. package/dist/ast/index.d.ts +5 -0
  11. package/dist/ast/index.d.ts.map +1 -0
  12. package/dist/ast/index.js +7 -0
  13. package/dist/ast/index.js.map +1 -0
  14. package/dist/ast/parser.d.ts +55 -0
  15. package/dist/ast/parser.d.ts.map +1 -0
  16. package/dist/ast/parser.js +210 -0
  17. package/dist/ast/parser.js.map +1 -0
  18. package/dist/ast/query.d.ts +48 -0
  19. package/dist/ast/query.d.ts.map +1 -0
  20. package/dist/ast/query.js +102 -0
  21. package/dist/ast/query.js.map +1 -0
  22. package/dist/ast/validate-cli.d.ts +21 -0
  23. package/dist/ast/validate-cli.d.ts.map +1 -0
  24. package/dist/ast/validate-cli.js +73 -0
  25. package/dist/ast/validate-cli.js.map +1 -0
  26. package/dist/cli.js +105 -21
  27. package/dist/cli.js.map +1 -1
  28. package/dist/compiler/builtins.d.ts.map +1 -1
  29. package/dist/compiler/builtins.js +721 -4
  30. package/dist/compiler/builtins.js.map +1 -1
  31. package/dist/compiler/commands.d.ts +40 -0
  32. package/dist/compiler/commands.d.ts.map +1 -0
  33. package/dist/compiler/commands.js +311 -0
  34. package/dist/compiler/commands.js.map +1 -0
  35. package/dist/compiler/content.d.ts +160 -0
  36. package/dist/compiler/content.d.ts.map +1 -0
  37. package/dist/compiler/content.js +461 -0
  38. package/dist/compiler/content.js.map +1 -0
  39. package/dist/compiler/index.d.ts.map +1 -1
  40. package/dist/compiler/index.js +34 -7
  41. package/dist/compiler/index.js.map +1 -1
  42. package/dist/compiler/llm.d.ts.map +1 -1
  43. package/dist/compiler/llm.js +96 -9
  44. package/dist/compiler/llm.js.map +1 -1
  45. package/dist/compiler/prompt.d.ts +1 -1
  46. package/dist/compiler/prompt.d.ts.map +1 -1
  47. package/dist/compiler/prompt.js +247 -15
  48. package/dist/compiler/prompt.js.map +1 -1
  49. package/dist/config/leash-parser.d.ts +29 -0
  50. package/dist/config/leash-parser.d.ts.map +1 -0
  51. package/dist/config/leash-parser.js +70 -0
  52. package/dist/config/leash-parser.js.map +1 -0
  53. package/dist/config/loader.d.ts +2 -1
  54. package/dist/config/loader.d.ts.map +1 -1
  55. package/dist/config/loader.js +18 -8
  56. package/dist/config/loader.js.map +1 -1
  57. package/dist/config/schema.d.ts +8 -0
  58. package/dist/config/schema.d.ts.map +1 -1
  59. package/dist/config/schema.js +19 -0
  60. package/dist/config/schema.js.map +1 -1
  61. package/dist/config/watcher.d.ts +18 -0
  62. package/dist/config/watcher.d.ts.map +1 -0
  63. package/dist/config/watcher.js +102 -0
  64. package/dist/config/watcher.js.map +1 -0
  65. package/dist/matcher.d.ts +18 -0
  66. package/dist/matcher.d.ts.map +1 -1
  67. package/dist/matcher.js +43 -0
  68. package/dist/matcher.js.map +1 -1
  69. package/dist/native/claude-code.d.ts.map +1 -1
  70. package/dist/native/claude-code.js +294 -50
  71. package/dist/native/claude-code.js.map +1 -1
  72. package/dist/native/cursor.d.ts +14 -1
  73. package/dist/native/cursor.d.ts.map +1 -1
  74. package/dist/native/cursor.js +340 -34
  75. package/dist/native/cursor.js.map +1 -1
  76. package/dist/native/index.d.ts +5 -0
  77. package/dist/native/index.d.ts.map +1 -1
  78. package/dist/native/index.js +56 -10
  79. package/dist/native/index.js.map +1 -1
  80. package/dist/native/opencode.d.ts.map +1 -1
  81. package/dist/native/opencode.js +15 -3
  82. package/dist/native/opencode.js.map +1 -1
  83. package/dist/native/validator.d.ts +15 -0
  84. package/dist/native/validator.d.ts.map +1 -0
  85. package/dist/native/validator.js +368 -0
  86. package/dist/native/validator.js.map +1 -0
  87. package/dist/types.d.ts +114 -0
  88. package/dist/types.d.ts.map +1 -1
  89. package/dist/types.js.map +1 -1
  90. package/dist/wrapper/daemon.d.ts.map +1 -1
  91. package/dist/wrapper/daemon.js +31 -2
  92. package/dist/wrapper/daemon.js.map +1 -1
  93. package/languages/tree-sitter-javascript.wasm +0 -0
  94. package/languages/tree-sitter-tsx.wasm +0 -0
  95. package/languages/tree-sitter-typescript.wasm +0 -0
  96. package/package.json +5 -2
@@ -1,28 +1,115 @@
1
1
  // src/compiler/llm.ts
2
- import { GoogleGenAI } from '@google/genai';
2
+ import { GoogleGenAI, Type } from '@google/genai';
3
3
  import { SYSTEM_PROMPT } from './prompt.js';
4
4
  // Native JSON schema - GUARANTEES valid output from Gemini
5
+ // Using Type enum for proper schema typing
5
6
  const POLICY_SCHEMA = {
6
- type: 'object',
7
+ type: Type.OBJECT,
7
8
  properties: {
8
9
  action: {
9
- type: 'string',
10
+ type: Type.STRING,
10
11
  enum: ['delete', 'modify', 'execute', 'read'],
12
+ description: 'The action type this policy restricts',
11
13
  },
12
14
  include: {
13
- type: 'array',
14
- items: { type: 'string' },
15
- description: 'Glob patterns for protected files',
15
+ type: Type.ARRAY,
16
+ items: { type: Type.STRING },
17
+ description: 'Glob patterns for protected files (can be empty for command-only policies)',
16
18
  },
17
19
  exclude: {
18
- type: 'array',
19
- items: { type: 'string' },
20
+ type: Type.ARRAY,
21
+ items: { type: Type.STRING },
20
22
  description: 'Glob patterns for safe exceptions',
21
23
  },
22
24
  description: {
23
- type: 'string',
25
+ type: Type.STRING,
24
26
  description: 'Human-readable description of what is protected',
25
27
  },
28
+ commandRules: {
29
+ type: Type.ARRAY,
30
+ description: 'Optional command-level rules for tool/command preferences',
31
+ items: {
32
+ type: Type.OBJECT,
33
+ properties: {
34
+ block: {
35
+ type: Type.ARRAY,
36
+ items: { type: Type.STRING },
37
+ description: 'Glob patterns for commands to block (e.g., "npm install*", "sudo *")',
38
+ },
39
+ suggest: {
40
+ type: Type.STRING,
41
+ description: 'Optional suggestion for alternative command',
42
+ },
43
+ reason: {
44
+ type: Type.STRING,
45
+ description: 'Human-readable reason for blocking',
46
+ },
47
+ },
48
+ required: ['block', 'reason'],
49
+ },
50
+ },
51
+ contentRules: {
52
+ type: Type.ARRAY,
53
+ description: 'Optional content-level rules to check file contents for banned patterns',
54
+ items: {
55
+ type: Type.OBJECT,
56
+ properties: {
57
+ pattern: {
58
+ type: Type.STRING,
59
+ description: 'Regex pattern to match in file content (e.g., "import.*lodash", "console\\.log")',
60
+ },
61
+ fileTypes: {
62
+ type: Type.ARRAY,
63
+ items: { type: Type.STRING },
64
+ description: 'File patterns where this rule applies (e.g., ["*.ts", "*.js"])',
65
+ },
66
+ reason: {
67
+ type: Type.STRING,
68
+ description: 'Human-readable reason for blocking',
69
+ },
70
+ suggest: {
71
+ type: Type.STRING,
72
+ description: 'Optional suggestion for alternative',
73
+ },
74
+ },
75
+ required: ['pattern', 'fileTypes', 'reason'],
76
+ },
77
+ },
78
+ astRules: {
79
+ type: Type.ARRAY,
80
+ description: 'Optional AST-based rules for precise code pattern matching (TypeScript/JavaScript only)',
81
+ items: {
82
+ type: Type.OBJECT,
83
+ properties: {
84
+ id: {
85
+ type: Type.STRING,
86
+ description: 'Unique identifier for this rule (e.g., "no-lodash-import")',
87
+ },
88
+ query: {
89
+ type: Type.STRING,
90
+ description: 'Tree-sitter S-expression query (e.g., "(import_statement source: (string) @s (#match? @s \\"lodash\\"))")',
91
+ },
92
+ languages: {
93
+ type: Type.ARRAY,
94
+ items: { type: Type.STRING },
95
+ description: 'Languages this rule applies to: ["typescript", "javascript"]',
96
+ },
97
+ reason: {
98
+ type: Type.STRING,
99
+ description: 'Human-readable reason for blocking',
100
+ },
101
+ suggest: {
102
+ type: Type.STRING,
103
+ description: 'Optional suggestion for alternative',
104
+ },
105
+ regexPreFilter: {
106
+ type: Type.STRING,
107
+ description: 'Fast pre-filter string - if content does not contain this, skip AST parsing',
108
+ },
109
+ },
110
+ required: ['id', 'query', 'languages', 'reason'],
111
+ },
112
+ },
26
113
  },
27
114
  required: ['action', 'include', 'exclude', 'description'],
28
115
  };
@@ -1 +1 @@
1
- {"version":3,"file":"llm.js","sourceRoot":"","sources":["../../src/compiler/llm.ts"],"names":[],"mappings":"AAAA,sBAAsB;AAEtB,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,2DAA2D;AAC3D,MAAM,aAAa,GAAG;IACpB,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE;QACV,MAAM,EAAE;YACN,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,CAAC;SAC9C;QACD,OAAO,EAAE;YACP,IAAI,EAAE,OAAO;YACb,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YACzB,WAAW,EAAE,mCAAmC;SACjD;QACD,OAAO,EAAE;YACP,IAAI,EAAE,OAAO;YACb,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YACzB,WAAW,EAAE,mCAAmC;SACjD;QACD,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,iDAAiD;SAC/D;KACF;IACD,QAAQ,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,aAAa,CAAC;CACjD,CAAC;AAEX,IAAI,EAAE,GAAuB,IAAI,CAAC;AAElC,SAAS,KAAK;IACZ,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;QAC1C,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;QAC5C,CAAC;QACD,EAAE,GAAG,IAAI,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IACnC,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,WAAmB,EACnB,eAAiC;IAEjC,MAAM,MAAM,GAAG,KAAK,EAAE,CAAC;IAEvB,MAAM,MAAM,GAAG,GAAG,aAAa;;gDAEe,eAAe;;gBAE/C,WAAW,GAAG,CAAC;IAE7B,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC;QACnD,KAAK,EAAE,kBAAkB;QACzB,QAAQ,EAAE,MAAM;QAChB,MAAM,EAAE;YACN,WAAW,EAAE,CAAC;YACd,eAAe,EAAE,GAAG;YACpB,gBAAgB,EAAE,kBAAkB;YACpC,cAAc,EAAE,aAAa;SAC9B;KACF,CAAC,CAAC;IAEH,yDAAyD;IACzD,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC;IAC3B,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;IAChD,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAW,CAAC;IAE1C,uDAAuD;IACvD,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QACnB,MAAM,CAAC,MAAM,GAAG,eAAe,CAAC;IAClC,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
1
+ {"version":3,"file":"llm.js","sourceRoot":"","sources":["../../src/compiler/llm.ts"],"names":[],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- export declare const SYSTEM_PROMPT = "You are a permission policy compiler for AI coding agents.\n\nConvert natural language restrictions into precise glob patterns.\n\nCRITICAL: Understand SEMANTIC INTENT, not just keywords.\n\nEXAMPLES OF SEMANTIC UNDERSTANDING:\n\n\"test files\" means TEST SOURCE CODE:\n include: [\"*.test.*\", \"*.spec.*\", \"__tests__/**\", \"test/**/*.ts\"]\n exclude: [\"test-results.*\", \"test-output.*\", \"coverage/**\"]\n \n\"config files\" means CONFIGURATION, not files that configure:\n include: [\"*.config.*\", \"tsconfig*\", \".eslintrc*\", \"vite.config.*\"]\n exclude: []\n\n\"env files\" means ENVIRONMENT SECRETS:\n include: [\".env\", \".env.*\", \"**/.env\", \"**/.env.*\"]\n exclude: [\".env.example\", \".env.template\"]\n\n\"migrations\" means DATABASE SCHEMA CHANGES:\n include: [\"**/migrations/**\", \"*migrate*\", \"prisma/migrations/**\"]\n exclude: []\n\nPATTERN RULES:\n- Always include **/ variants for recursive matching\n- \"starts with X\" \u2192 [\"X*\", \"**/X*\"] \n- \"ends with X\" \u2192 [\"*X\", \"**/*X\"]\n- \"contains X\" \u2192 [\"*X*\", \"**/*X*\"]\n- \"in directory X\" \u2192 [\"X/**\"]\n\nINCLUDE = what to PROTECT (be generous)\nEXCLUDE = what to ALLOW (carve out exceptions)\n\nOutput JSON only. No explanation.";
1
+ export declare const SYSTEM_PROMPT = "You are a permission policy compiler for AI coding agents.\n\nConvert natural language restrictions into precise, COMPREHENSIVE patterns.\n\nCRITICAL: \n1. Understand SEMANTIC INTENT, not just keywords\n2. Generate MULTIPLE patterns to catch ALL variants of a violation\n3. Use 'strict' mode to avoid false positives in comments/strings\n4. Include 'exceptions' patterns to prevent false positives\n5. For TypeScript/JavaScript code patterns, prefer astRules over contentRules (zero false positives)\n\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nBUILT-IN AST RULES (DO NOT REGENERATE)\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\nThese restrictions have pre-built AST rules. Return ONLY the basic policy structure:\n- \"no lodash\" \u2192 handled by builtin\n- \"no moment\" \u2192 handled by builtin \n- \"no jquery\" \u2192 handled by builtin\n- \"no axios\" \u2192 handled by builtin\n- \"no any\" / \"no any types\" \u2192 handled by builtin\n- \"no console\" / \"no console.log\" \u2192 handled by builtin\n- \"no eval\" \u2192 handled by builtin\n- \"no innerhtml\" \u2192 handled by builtin\n- \"no debugger\" \u2192 handled by builtin\n- \"no var\" \u2192 handled by builtin\n- \"no alert\" \u2192 handled by builtin\n- \"no class components\" \u2192 handled by builtin\n\nFor these, return minimal policy:\n{\n \"action\": \"modify\",\n \"include\": [\"**/*.ts\", \"**/*.tsx\", \"**/*.js\", \"**/*.jsx\"],\n \"exclude\": [],\n \"description\": \"<the restriction>\"\n}\n\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nFILE-LEVEL POLICIES (include/exclude patterns)\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\n\"test files\" means TEST SOURCE CODE:\n include: [\"*.test.*\", \"*.spec.*\", \"__tests__/**\", \"test/**/*.ts\"]\n exclude: [\"test-results.*\", \"test-output.*\", \"coverage/**\"]\n \n\"config files\" means CONFIGURATION:\n include: [\"*.config.*\", \"tsconfig*\", \".eslintrc*\", \"vite.config.*\"]\n exclude: []\n\n\"env files\" means ENVIRONMENT SECRETS:\n include: [\".env\", \".env.*\", \"**/.env\", \"**/.env.*\"]\n exclude: [\".env.example\", \".env.template\"]\n\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nCOMMAND-LEVEL POLICIES (commandRules)\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\nFor tool/command preferences, generate commandRules array.\n\n\"prefer pnpm\" or \"use pnpm not npm\":\n commandRules: [\n { block: [\"npm install*\", \"npm i *\", \"npm i\", \"npm ci\"], suggest: \"pnpm install\", reason: \"Project uses pnpm\" }\n ]\n\nCOMMAND PATTERN RULES:\n- \"command *\" matches command with any args\n- Include common aliases: npm i = npm install, bun a = bun add\n\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nCONTENT-LEVEL POLICIES (contentRules) - COMPREHENSIVE\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\nCRITICAL: Generate MULTIPLE patterns to catch ALL import/usage variants.\n\n\"no lodash\" - Must catch ALL these forms:\n contentRules: [\n {\n pattern: \"(?:import|require)\\\\s*(?:\\\\(|\\\\s).*['\"]lodash(?:[-./][^'\"]*)?['\"]\",\n fileTypes: [\"*.ts\", \"*.js\", \"*.tsx\", \"*.jsx\"],\n reason: \"Use native methods instead of lodash\",\n suggest: \"Use Array.map(), filter(), Object.keys()\",\n mode: \"strict\"\n }\n ]\n // This catches:\n // - import _ from 'lodash'\n // - import { map } from 'lodash'\n // - import * as _ from 'lodash'\n // - import map from 'lodash/map'\n // - import map from 'lodash.map'\n // - import _ from 'lodash-es'\n // - require('lodash')\n // - await import('lodash')\n\n\"no any types\" - Must catch ALL these forms:\n contentRules: [\n {\n pattern: \"(?::\\\\s*any\\\\s*(?:[,;)\\\\]=]|$)|<\\\\s*any\\\\s*>|as\\\\s+any\\\\b)\",\n fileTypes: [\"*.ts\", \"*.tsx\"],\n reason: \"Use proper TypeScript types\",\n suggest: \"Use unknown or specific types\",\n mode: \"strict\",\n exceptions: [\"(?:const|let|var|function)\\\\s+\\\\w*any\\\\w*\"]\n },\n {\n pattern: \"Array\\\\s*<\\\\s*any\\\\s*>\",\n fileTypes: [\"*.ts\", \"*.tsx\"],\n reason: \"Avoid Array<any>\",\n mode: \"strict\"\n },\n {\n pattern: \"Record\\\\s*<[^>]*,\\\\s*any\\\\s*>\",\n fileTypes: [\"*.ts\", \"*.tsx\"],\n reason: \"Avoid Record<string, any>\",\n mode: \"strict\"\n },\n {\n pattern: \"type\\\\s+\\\\w+\\\\s*=\\\\s*any\\\\s*;\",\n fileTypes: [\"*.ts\", \"*.tsx\"],\n reason: \"Avoid type alias to any\",\n mode: \"strict\"\n }\n ]\n // This catches:\n // - : any\n // - <any>\n // - as any\n // - Array<any>\n // - Record<string, any>\n // - Promise<any>\n // - type Foo = any\n // - <T = any>\n // But NOT:\n // - const anyValue = 5 (variable name)\n // - \"any\" in strings (mode: strict)\n // - // any in comments (mode: strict)\n\n\"no console.log\" - Must catch ALL these forms:\n contentRules: [\n {\n pattern: \"\\\\bconsole\\\\s*\\\\.\\\\s*log\\\\s*\\\\(\",\n fileTypes: [\"*.ts\", \"*.js\"],\n reason: \"Use proper logging\",\n mode: \"strict\"\n },\n {\n pattern: \"console\\\\s*\\\\[\\\\s*['\"]log['\"]\\\\s*\\\\]\",\n fileTypes: [\"*.ts\", \"*.js\"],\n reason: \"Console accessed via bracket notation\",\n mode: \"strict\"\n },\n {\n pattern: \"\\\\{\\\\s*log(?:\\\\s*:\\\\s*\\\\w+)?\\\\s*\\\\}\\\\s*=\\\\s*console\",\n fileTypes: [\"*.ts\", \"*.js\"],\n reason: \"Destructured console.log detected\",\n mode: \"strict\"\n }\n ]\n // This catches:\n // - console.log(\n // - console['log'](\n // - const { log } = console\n // - const { log: myLog } = console\n\n\"no class components\" (React):\n contentRules: [\n {\n pattern: \"class\\\\s+\\\\w+\\\\s+extends\\\\s+(?:React\\\\s*\\\\.\\\\s*)?(?:Pure)?Component\\\\s*(?:<|\\\\{)\",\n fileTypes: [\"*.tsx\", \"*.jsx\"],\n reason: \"Use functional components with hooks\",\n suggest: \"const Component = () => { ... }\",\n mode: \"strict\"\n }\n ]\n // This catches:\n // - class Foo extends Component {\n // - class Foo extends React.Component {\n // - class Foo extends PureComponent {\n // - class Foo extends Component<Props> {\n\n\"no eval\" - Must catch ALL unsafe eval-like constructs:\n contentRules: [\n {\n pattern: \"\\\\beval\\\\s*\\\\(\",\n fileTypes: [\"*.ts\", \"*.js\"],\n reason: \"eval() is a security risk\",\n mode: \"strict\"\n },\n {\n pattern: \"new\\\\s+Function\\\\s*\\\\(\",\n fileTypes: [\"*.ts\", \"*.js\"],\n reason: \"new Function() is equivalent to eval()\",\n mode: \"strict\"\n },\n {\n pattern: \"setTimeout\\\\s*\\\\(\\\\s*['\"]\",\n fileTypes: [\"*.ts\", \"*.js\"],\n reason: \"setTimeout with string is eval-like\",\n mode: \"strict\"\n }\n ]\n\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nCONTENT RULE OPTIONS\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\nmode (optional):\n - \"fast\": Direct regex match (default, fastest, may have false positives)\n - \"strict\": Strip comments/strings before matching (recommended for most rules)\n\nexceptions (optional):\n - Array of regex patterns that indicate FALSE POSITIVES\n - If exception matches context around the main match, rule is NOT violated\n - Example: Don't flag 'any' in variable names like 'anyValue'\n\nfileTypes:\n - Array of glob patterns: [\"*.ts\", \"*.tsx\", \"*.js\"]\n - Use specific types, not broad patterns\n\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nAST RULES (PREFERRED FOR TS/JS - ZERO FALSE POSITIVES)\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\nFor TypeScript/JavaScript code patterns NOT covered by builtins, generate astRules.\nAST rules use tree-sitter S-expression queries - they NEVER match comments or strings.\n\nFormat:\n astRules: [{\n id: \"unique-rule-id\",\n query: \"(tree_sitter_query) @capture\",\n languages: [\"typescript\", \"javascript\"],\n reason: \"Why this is blocked\",\n suggest: \"Alternative approach\",\n regexPreFilter: \"fast_string_check\"\n }]\n\nCommon query patterns:\n (import_statement source: (string) @s (#match? @s \"pattern\")) - imports\n (call_expression function: (identifier) @fn (#eq? @fn \"name\")) - function calls\n (type_annotation (predefined_type) @t (#eq? @t \"any\")) - type annotations\n\nALWAYS include regexPreFilter for performance (skips AST if string not found).\n\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nBEST PRACTICES\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\n1. ALWAYS generate multiple contentRules to catch ALL variants\n2. USE mode: \"strict\" for patterns that might appear in comments/strings\n3. ADD exceptions for common false positive patterns\n4. INCLUDE word boundaries (\\b) to avoid partial matches\n5. For imports, catch: ES6 import, CommonJS require, dynamic import, submodules\n6. For types, catch: annotations, generics, assertions, aliases\n7. For function calls, catch: direct calls, bracket notation, destructuring\n\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nDECISION TREE\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\n1. If about FILES (test files, .env, configs) \u2192 use include/exclude\n2. If about COMMANDS/TOOLS (npm vs pnpm, jest vs vitest) \u2192 use commandRules\n3. If about TS/JS CODE PATTERNS and matches a builtin \u2192 return minimal policy (handled by builtin)\n4. If about TS/JS CODE PATTERNS not covered by builtin \u2192 use astRules (zero false positives)\n5. If about non-TS/JS CODE PATTERNS \u2192 use contentRules with mode: \"strict\"\n6. If about PREVENTING PACKAGE \u2192 use commandRules + astRules (or contentRules for non-JS)\n\nOutput JSON only. No explanation.";
2
2
  //# sourceMappingURL=prompt.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../src/compiler/prompt.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,aAAa,8uCAkCQ,CAAC"}
1
+ {"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../src/compiler/prompt.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,aAAa,gtdA0QQ,CAAC"}
@@ -1,17 +1,50 @@
1
1
  // src/compiler/prompt.ts
2
2
  export const SYSTEM_PROMPT = `You are a permission policy compiler for AI coding agents.
3
3
 
4
- Convert natural language restrictions into precise glob patterns.
4
+ Convert natural language restrictions into precise, COMPREHENSIVE patterns.
5
5
 
6
- CRITICAL: Understand SEMANTIC INTENT, not just keywords.
6
+ CRITICAL:
7
+ 1. Understand SEMANTIC INTENT, not just keywords
8
+ 2. Generate MULTIPLE patterns to catch ALL variants of a violation
9
+ 3. Use 'strict' mode to avoid false positives in comments/strings
10
+ 4. Include 'exceptions' patterns to prevent false positives
11
+ 5. For TypeScript/JavaScript code patterns, prefer astRules over contentRules (zero false positives)
7
12
 
8
- EXAMPLES OF SEMANTIC UNDERSTANDING:
13
+ ═══════════════════════════════════════════════════════════════
14
+ BUILT-IN AST RULES (DO NOT REGENERATE)
15
+ ═══════════════════════════════════════════════════════════════
16
+
17
+ These restrictions have pre-built AST rules. Return ONLY the basic policy structure:
18
+ - "no lodash" → handled by builtin
19
+ - "no moment" → handled by builtin
20
+ - "no jquery" → handled by builtin
21
+ - "no axios" → handled by builtin
22
+ - "no any" / "no any types" → handled by builtin
23
+ - "no console" / "no console.log" → handled by builtin
24
+ - "no eval" → handled by builtin
25
+ - "no innerhtml" → handled by builtin
26
+ - "no debugger" → handled by builtin
27
+ - "no var" → handled by builtin
28
+ - "no alert" → handled by builtin
29
+ - "no class components" → handled by builtin
30
+
31
+ For these, return minimal policy:
32
+ {
33
+ "action": "modify",
34
+ "include": ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx"],
35
+ "exclude": [],
36
+ "description": "<the restriction>"
37
+ }
38
+
39
+ ═══════════════════════════════════════════════════════════════
40
+ FILE-LEVEL POLICIES (include/exclude patterns)
41
+ ═══════════════════════════════════════════════════════════════
9
42
 
10
43
  "test files" means TEST SOURCE CODE:
11
44
  include: ["*.test.*", "*.spec.*", "__tests__/**", "test/**/*.ts"]
12
45
  exclude: ["test-results.*", "test-output.*", "coverage/**"]
13
46
 
14
- "config files" means CONFIGURATION, not files that configure:
47
+ "config files" means CONFIGURATION:
15
48
  include: ["*.config.*", "tsconfig*", ".eslintrc*", "vite.config.*"]
16
49
  exclude: []
17
50
 
@@ -19,19 +52,218 @@ EXAMPLES OF SEMANTIC UNDERSTANDING:
19
52
  include: [".env", ".env.*", "**/.env", "**/.env.*"]
20
53
  exclude: [".env.example", ".env.template"]
21
54
 
22
- "migrations" means DATABASE SCHEMA CHANGES:
23
- include: ["**/migrations/**", "*migrate*", "prisma/migrations/**"]
24
- exclude: []
55
+ ═══════════════════════════════════════════════════════════════
56
+ COMMAND-LEVEL POLICIES (commandRules)
57
+ ═══════════════════════════════════════════════════════════════
58
+
59
+ For tool/command preferences, generate commandRules array.
60
+
61
+ "prefer pnpm" or "use pnpm not npm":
62
+ commandRules: [
63
+ { block: ["npm install*", "npm i *", "npm i", "npm ci"], suggest: "pnpm install", reason: "Project uses pnpm" }
64
+ ]
65
+
66
+ COMMAND PATTERN RULES:
67
+ - "command *" matches command with any args
68
+ - Include common aliases: npm i = npm install, bun a = bun add
69
+
70
+ ═══════════════════════════════════════════════════════════════
71
+ CONTENT-LEVEL POLICIES (contentRules) - COMPREHENSIVE
72
+ ═══════════════════════════════════════════════════════════════
73
+
74
+ CRITICAL: Generate MULTIPLE patterns to catch ALL import/usage variants.
75
+
76
+ "no lodash" - Must catch ALL these forms:
77
+ contentRules: [
78
+ {
79
+ pattern: "(?:import|require)\\\\s*(?:\\\\(|\\\\s).*['\"]lodash(?:[-./][^'\"]*)?['\"]",
80
+ fileTypes: ["*.ts", "*.js", "*.tsx", "*.jsx"],
81
+ reason: "Use native methods instead of lodash",
82
+ suggest: "Use Array.map(), filter(), Object.keys()",
83
+ mode: "strict"
84
+ }
85
+ ]
86
+ // This catches:
87
+ // - import _ from 'lodash'
88
+ // - import { map } from 'lodash'
89
+ // - import * as _ from 'lodash'
90
+ // - import map from 'lodash/map'
91
+ // - import map from 'lodash.map'
92
+ // - import _ from 'lodash-es'
93
+ // - require('lodash')
94
+ // - await import('lodash')
95
+
96
+ "no any types" - Must catch ALL these forms:
97
+ contentRules: [
98
+ {
99
+ pattern: "(?::\\\\s*any\\\\s*(?:[,;)\\\\]=]|$)|<\\\\s*any\\\\s*>|as\\\\s+any\\\\b)",
100
+ fileTypes: ["*.ts", "*.tsx"],
101
+ reason: "Use proper TypeScript types",
102
+ suggest: "Use unknown or specific types",
103
+ mode: "strict",
104
+ exceptions: ["(?:const|let|var|function)\\\\s+\\\\w*any\\\\w*"]
105
+ },
106
+ {
107
+ pattern: "Array\\\\s*<\\\\s*any\\\\s*>",
108
+ fileTypes: ["*.ts", "*.tsx"],
109
+ reason: "Avoid Array<any>",
110
+ mode: "strict"
111
+ },
112
+ {
113
+ pattern: "Record\\\\s*<[^>]*,\\\\s*any\\\\s*>",
114
+ fileTypes: ["*.ts", "*.tsx"],
115
+ reason: "Avoid Record<string, any>",
116
+ mode: "strict"
117
+ },
118
+ {
119
+ pattern: "type\\\\s+\\\\w+\\\\s*=\\\\s*any\\\\s*;",
120
+ fileTypes: ["*.ts", "*.tsx"],
121
+ reason: "Avoid type alias to any",
122
+ mode: "strict"
123
+ }
124
+ ]
125
+ // This catches:
126
+ // - : any
127
+ // - <any>
128
+ // - as any
129
+ // - Array<any>
130
+ // - Record<string, any>
131
+ // - Promise<any>
132
+ // - type Foo = any
133
+ // - <T = any>
134
+ // But NOT:
135
+ // - const anyValue = 5 (variable name)
136
+ // - "any" in strings (mode: strict)
137
+ // - // any in comments (mode: strict)
138
+
139
+ "no console.log" - Must catch ALL these forms:
140
+ contentRules: [
141
+ {
142
+ pattern: "\\\\bconsole\\\\s*\\\\.\\\\s*log\\\\s*\\\\(",
143
+ fileTypes: ["*.ts", "*.js"],
144
+ reason: "Use proper logging",
145
+ mode: "strict"
146
+ },
147
+ {
148
+ pattern: "console\\\\s*\\\\[\\\\s*['\"]log['\"]\\\\s*\\\\]",
149
+ fileTypes: ["*.ts", "*.js"],
150
+ reason: "Console accessed via bracket notation",
151
+ mode: "strict"
152
+ },
153
+ {
154
+ pattern: "\\\\{\\\\s*log(?:\\\\s*:\\\\s*\\\\w+)?\\\\s*\\\\}\\\\s*=\\\\s*console",
155
+ fileTypes: ["*.ts", "*.js"],
156
+ reason: "Destructured console.log detected",
157
+ mode: "strict"
158
+ }
159
+ ]
160
+ // This catches:
161
+ // - console.log(
162
+ // - console['log'](
163
+ // - const { log } = console
164
+ // - const { log: myLog } = console
165
+
166
+ "no class components" (React):
167
+ contentRules: [
168
+ {
169
+ pattern: "class\\\\s+\\\\w+\\\\s+extends\\\\s+(?:React\\\\s*\\\\.\\\\s*)?(?:Pure)?Component\\\\s*(?:<|\\\\{)",
170
+ fileTypes: ["*.tsx", "*.jsx"],
171
+ reason: "Use functional components with hooks",
172
+ suggest: "const Component = () => { ... }",
173
+ mode: "strict"
174
+ }
175
+ ]
176
+ // This catches:
177
+ // - class Foo extends Component {
178
+ // - class Foo extends React.Component {
179
+ // - class Foo extends PureComponent {
180
+ // - class Foo extends Component<Props> {
181
+
182
+ "no eval" - Must catch ALL unsafe eval-like constructs:
183
+ contentRules: [
184
+ {
185
+ pattern: "\\\\beval\\\\s*\\\\(",
186
+ fileTypes: ["*.ts", "*.js"],
187
+ reason: "eval() is a security risk",
188
+ mode: "strict"
189
+ },
190
+ {
191
+ pattern: "new\\\\s+Function\\\\s*\\\\(",
192
+ fileTypes: ["*.ts", "*.js"],
193
+ reason: "new Function() is equivalent to eval()",
194
+ mode: "strict"
195
+ },
196
+ {
197
+ pattern: "setTimeout\\\\s*\\\\(\\\\s*['\"]",
198
+ fileTypes: ["*.ts", "*.js"],
199
+ reason: "setTimeout with string is eval-like",
200
+ mode: "strict"
201
+ }
202
+ ]
203
+
204
+ ═══════════════════════════════════════════════════════════════
205
+ CONTENT RULE OPTIONS
206
+ ═══════════════════════════════════════════════════════════════
207
+
208
+ mode (optional):
209
+ - "fast": Direct regex match (default, fastest, may have false positives)
210
+ - "strict": Strip comments/strings before matching (recommended for most rules)
211
+
212
+ exceptions (optional):
213
+ - Array of regex patterns that indicate FALSE POSITIVES
214
+ - If exception matches context around the main match, rule is NOT violated
215
+ - Example: Don't flag 'any' in variable names like 'anyValue'
216
+
217
+ fileTypes:
218
+ - Array of glob patterns: ["*.ts", "*.tsx", "*.js"]
219
+ - Use specific types, not broad patterns
220
+
221
+ ═══════════════════════════════════════════════════════════════
222
+ AST RULES (PREFERRED FOR TS/JS - ZERO FALSE POSITIVES)
223
+ ═══════════════════════════════════════════════════════════════
224
+
225
+ For TypeScript/JavaScript code patterns NOT covered by builtins, generate astRules.
226
+ AST rules use tree-sitter S-expression queries - they NEVER match comments or strings.
227
+
228
+ Format:
229
+ astRules: [{
230
+ id: "unique-rule-id",
231
+ query: "(tree_sitter_query) @capture",
232
+ languages: ["typescript", "javascript"],
233
+ reason: "Why this is blocked",
234
+ suggest: "Alternative approach",
235
+ regexPreFilter: "fast_string_check"
236
+ }]
237
+
238
+ Common query patterns:
239
+ (import_statement source: (string) @s (#match? @s "pattern")) - imports
240
+ (call_expression function: (identifier) @fn (#eq? @fn "name")) - function calls
241
+ (type_annotation (predefined_type) @t (#eq? @t "any")) - type annotations
242
+
243
+ ALWAYS include regexPreFilter for performance (skips AST if string not found).
244
+
245
+ ═══════════════════════════════════════════════════════════════
246
+ BEST PRACTICES
247
+ ═══════════════════════════════════════════════════════════════
248
+
249
+ 1. ALWAYS generate multiple contentRules to catch ALL variants
250
+ 2. USE mode: "strict" for patterns that might appear in comments/strings
251
+ 3. ADD exceptions for common false positive patterns
252
+ 4. INCLUDE word boundaries (\\b) to avoid partial matches
253
+ 5. For imports, catch: ES6 import, CommonJS require, dynamic import, submodules
254
+ 6. For types, catch: annotations, generics, assertions, aliases
255
+ 7. For function calls, catch: direct calls, bracket notation, destructuring
25
256
 
26
- PATTERN RULES:
27
- - Always include **/ variants for recursive matching
28
- - "starts with X" → ["X*", "**/X*"]
29
- - "ends with X" → ["*X", "**/*X"]
30
- - "contains X" → ["*X*", "**/*X*"]
31
- - "in directory X" → ["X/**"]
257
+ ═══════════════════════════════════════════════════════════════
258
+ DECISION TREE
259
+ ═══════════════════════════════════════════════════════════════
32
260
 
33
- INCLUDE = what to PROTECT (be generous)
34
- EXCLUDE = what to ALLOW (carve out exceptions)
261
+ 1. If about FILES (test files, .env, configs) → use include/exclude
262
+ 2. If about COMMANDS/TOOLS (npm vs pnpm, jest vs vitest) → use commandRules
263
+ 3. If about TS/JS CODE PATTERNS and matches a builtin → return minimal policy (handled by builtin)
264
+ 4. If about TS/JS CODE PATTERNS not covered by builtin → use astRules (zero false positives)
265
+ 5. If about non-TS/JS CODE PATTERNS → use contentRules with mode: "strict"
266
+ 6. If about PREVENTING PACKAGE → use commandRules + astRules (or contentRules for non-JS)
35
267
 
36
268
  Output JSON only. No explanation.`;
37
269
  //# sourceMappingURL=prompt.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/compiler/prompt.ts"],"names":[],"mappings":"AAAA,yBAAyB;AAEzB,MAAM,CAAC,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kCAkCK,CAAC"}
1
+ {"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/compiler/prompt.ts"],"names":[],"mappings":"AAAA,yBAAyB;AAEzB,MAAM,CAAC,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kCA0QK,CAAC"}
@@ -0,0 +1,29 @@
1
+ export interface LeashPolicy {
2
+ raw: string;
3
+ restriction: string;
4
+ reason?: string;
5
+ extend?: string;
6
+ }
7
+ /**
8
+ * Parse a simple .leash file into policies.
9
+ *
10
+ * Format:
11
+ * # Comment lines start with #
12
+ * no lodash
13
+ * no any types - enforces strict TypeScript
14
+ * extend @acme/typescript-strict
15
+ */
16
+ export declare function parseLeashFile(content: string): LeashPolicy[];
17
+ /**
18
+ * Detect if content is simple .leash format (not YAML).
19
+ * YAML format has 'version:' or 'policies:' keys.
20
+ */
21
+ export declare function isSimpleLeashFormat(content: string): boolean;
22
+ /**
23
+ * Convert parsed policies to the internal LeashConfig format.
24
+ */
25
+ export declare function policiesToConfig(policies: LeashPolicy[]): {
26
+ version: 1;
27
+ policies: string[];
28
+ };
29
+ //# sourceMappingURL=leash-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"leash-parser.d.ts","sourceRoot":"","sources":["../../src/config/leash-parser.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,EAAE,CAM7D;AAqBD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAiB5D;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,WAAW,EAAE,GAAG;IAAE,OAAO,EAAE,CAAC,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAO5F"}
@@ -0,0 +1,70 @@
1
+ // src/config/leash-parser.ts
2
+ // Simple plain-text .leash file parser
3
+ // Format: one policy per line, # for comments, ` - ` for optional reason
4
+ /**
5
+ * Parse a simple .leash file into policies.
6
+ *
7
+ * Format:
8
+ * # Comment lines start with #
9
+ * no lodash
10
+ * no any types - enforces strict TypeScript
11
+ * extend @acme/typescript-strict
12
+ */
13
+ export function parseLeashFile(content) {
14
+ return content
15
+ .split('\n')
16
+ .map(line => line.trim())
17
+ .filter(line => line && !line.startsWith('#'))
18
+ .map(parseLine);
19
+ }
20
+ function parseLine(line) {
21
+ // Handle extend directive
22
+ if (line.startsWith('extend ')) {
23
+ const target = line.slice(7).trim();
24
+ return { raw: line, restriction: '', extend: target };
25
+ }
26
+ // Split by ' - ' for optional reason
27
+ const dashIndex = line.indexOf(' - ');
28
+ if (dashIndex !== -1) {
29
+ const restriction = line.slice(0, dashIndex).trim();
30
+ const reason = line.slice(dashIndex + 3).trim();
31
+ return { raw: line, restriction, reason };
32
+ }
33
+ // Simple policy without reason
34
+ return { raw: line, restriction: line };
35
+ }
36
+ /**
37
+ * Detect if content is simple .leash format (not YAML).
38
+ * YAML format has 'version:' or 'policies:' keys.
39
+ */
40
+ export function isSimpleLeashFormat(content) {
41
+ const trimmed = content.trim();
42
+ // Empty file = simple format (will result in no policies)
43
+ if (!trimmed)
44
+ return true;
45
+ // Check first meaningful line
46
+ const lines = trimmed.split('\n').map(l => l.trim()).filter(l => l && !l.startsWith('#'));
47
+ if (lines.length === 0)
48
+ return true;
49
+ // YAML indicators
50
+ const firstLine = lines[0];
51
+ if (firstLine.startsWith('version:'))
52
+ return false;
53
+ if (firstLine.startsWith('policies:'))
54
+ return false;
55
+ if (firstLine.startsWith('{'))
56
+ return false; // JSON
57
+ return true;
58
+ }
59
+ /**
60
+ * Convert parsed policies to the internal LeashConfig format.
61
+ */
62
+ export function policiesToConfig(policies) {
63
+ return {
64
+ version: 1,
65
+ policies: policies
66
+ .filter(p => p.restriction) // Skip extend directives for now
67
+ .map(p => p.restriction),
68
+ };
69
+ }
70
+ //# sourceMappingURL=leash-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"leash-parser.js","sourceRoot":"","sources":["../../src/config/leash-parser.ts"],"names":[],"mappings":"AAAA,6BAA6B;AAC7B,uCAAuC;AACvC,yEAAyE;AASzE;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAAC,OAAe;IAC5C,OAAO,OAAO;SACX,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SACxB,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;SAC7C,GAAG,CAAC,SAAS,CAAC,CAAC;AACpB,CAAC;AAED,SAAS,SAAS,CAAC,IAAY;IAC7B,0BAA0B;IAC1B,IAAI,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACpC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IACxD,CAAC;IAED,qCAAqC;IACrC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACtC,IAAI,SAAS,KAAK,CAAC,CAAC,EAAE,CAAC;QACrB,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,IAAI,EAAE,CAAC;QACpD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAChD,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC;IAC5C,CAAC;IAED,+BAA+B;IAC/B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;AAC1C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAe;IACjD,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IAE/B,0DAA0D;IAC1D,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAE1B,8BAA8B;IAC9B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1F,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEpC,kBAAkB;IAClB,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAC3B,IAAI,SAAS,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,KAAK,CAAC;IACnD,IAAI,SAAS,CAAC,UAAU,CAAC,WAAW,CAAC;QAAE,OAAO,KAAK,CAAC;IACpD,IAAI,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC,CAAE,OAAO;IAErD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAuB;IACtD,OAAO;QACL,OAAO,EAAE,CAAC;QACV,QAAQ,EAAE,QAAQ;aACf,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAE,iCAAiC;aAC7D,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC;KAC3B,CAAC;AACJ,CAAC"}
@@ -5,6 +5,7 @@ import { type LeashConfig, type CompiledLeashConfig } from './schema.js';
5
5
  export declare function findLeashConfig(dir?: string): string | null;
6
6
  /**
7
7
  * Load and parse .leash config
8
+ * Supports both simple plain-text format and YAML format.
8
9
  */
9
10
  export declare function loadLeashConfig(path: string): LeashConfig | null;
10
11
  /**
@@ -12,7 +13,7 @@ export declare function loadLeashConfig(path: string): LeashConfig | null;
12
13
  */
13
14
  export declare function compileLeashConfig(config: LeashConfig): Promise<CompiledLeashConfig>;
14
15
  /**
15
- * Create a new .leash config file
16
+ * Create a new .leash config file (simple plain-text format)
16
17
  */
17
18
  export declare function createLeashConfig(dir?: string): string;
18
19
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAMA,OAAO,EAKL,KAAK,WAAW,EAChB,KAAK,mBAAmB,EACzB,MAAM,aAAa,CAAC;AASrB;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,GAAE,MAAsB,GAAG,MAAM,GAAG,IAAI,CAW1E;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CA0BhE;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,mBAAmB,CAAC,CAwB9B;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,GAAE,MAAsB,GAAG,MAAM,CAerE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAEnE"}
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAMA,OAAO,EAKL,KAAK,WAAW,EAChB,KAAK,mBAAmB,EACzB,MAAM,aAAa,CAAC;AAUrB;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,GAAE,MAAsB,GAAG,MAAM,GAAG,IAAI,CAW1E;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAmChE;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,mBAAmB,CAAC,CAwB9B;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,GAAE,MAAsB,GAAG,MAAM,CAcrE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAEnE"}