@mwturnbull/papi-mcp 0.1.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.
Files changed (87) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +320 -0
  3. package/dist/config/assembler.d.ts +6 -0
  4. package/dist/config/assembler.d.ts.map +1 -0
  5. package/dist/config/assembler.js +56 -0
  6. package/dist/config/assembler.js.map +1 -0
  7. package/dist/config/parser.d.ts +6 -0
  8. package/dist/config/parser.d.ts.map +1 -0
  9. package/dist/config/parser.js +79 -0
  10. package/dist/config/parser.js.map +1 -0
  11. package/dist/config/snippets.d.ts +12 -0
  12. package/dist/config/snippets.d.ts.map +1 -0
  13. package/dist/config/snippets.js +75 -0
  14. package/dist/config/snippets.js.map +1 -0
  15. package/dist/git/git-ops.d.ts +16 -0
  16. package/dist/git/git-ops.d.ts.map +1 -0
  17. package/dist/git/git-ops.js +64 -0
  18. package/dist/git/git-ops.js.map +1 -0
  19. package/dist/git/github.d.ts +12 -0
  20. package/dist/git/github.d.ts.map +1 -0
  21. package/dist/git/github.js +83 -0
  22. package/dist/git/github.js.map +1 -0
  23. package/dist/git/gitlab.d.ts +11 -0
  24. package/dist/git/gitlab.d.ts.map +1 -0
  25. package/dist/git/gitlab.js +65 -0
  26. package/dist/git/gitlab.js.map +1 -0
  27. package/dist/git/provider.d.ts +33 -0
  28. package/dist/git/provider.d.ts.map +1 -0
  29. package/dist/git/provider.js +49 -0
  30. package/dist/git/provider.js.map +1 -0
  31. package/dist/papi/auth.d.ts +12 -0
  32. package/dist/papi/auth.d.ts.map +1 -0
  33. package/dist/papi/auth.js +74 -0
  34. package/dist/papi/auth.js.map +1 -0
  35. package/dist/papi/client.d.ts +19 -0
  36. package/dist/papi/client.d.ts.map +1 -0
  37. package/dist/papi/client.js +115 -0
  38. package/dist/papi/client.js.map +1 -0
  39. package/dist/papi/types.d.ts +487 -0
  40. package/dist/papi/types.d.ts.map +1 -0
  41. package/dist/papi/types.js +94 -0
  42. package/dist/papi/types.js.map +1 -0
  43. package/dist/redaction/redactor.d.ts +25 -0
  44. package/dist/redaction/redactor.d.ts.map +1 -0
  45. package/dist/redaction/redactor.js +128 -0
  46. package/dist/redaction/redactor.js.map +1 -0
  47. package/dist/server.d.ts +3 -0
  48. package/dist/server.d.ts.map +1 -0
  49. package/dist/server.js +219 -0
  50. package/dist/server.js.map +1 -0
  51. package/dist/tools/activate.d.ts +16 -0
  52. package/dist/tools/activate.d.ts.map +1 -0
  53. package/dist/tools/activate.js +59 -0
  54. package/dist/tools/activate.js.map +1 -0
  55. package/dist/tools/diff-configs.d.ts +3 -0
  56. package/dist/tools/diff-configs.d.ts.map +1 -0
  57. package/dist/tools/diff-configs.js +152 -0
  58. package/dist/tools/diff-configs.js.map +1 -0
  59. package/dist/tools/get-property-config.d.ts +9 -0
  60. package/dist/tools/get-property-config.d.ts.map +1 -0
  61. package/dist/tools/get-property-config.js +53 -0
  62. package/dist/tools/get-property-config.js.map +1 -0
  63. package/dist/tools/pipeline.d.ts +11 -0
  64. package/dist/tools/pipeline.d.ts.map +1 -0
  65. package/dist/tools/pipeline.js +9 -0
  66. package/dist/tools/pipeline.js.map +1 -0
  67. package/dist/tools/sync-property.d.ts +9 -0
  68. package/dist/tools/sync-property.d.ts.map +1 -0
  69. package/dist/tools/sync-property.js +65 -0
  70. package/dist/tools/sync-property.js.map +1 -0
  71. package/dist/tools/write-snippet.d.ts +30 -0
  72. package/dist/tools/write-snippet.d.ts.map +1 -0
  73. package/dist/tools/write-snippet.js +92 -0
  74. package/dist/tools/write-snippet.js.map +1 -0
  75. package/dist/validation/local.d.ts +3 -0
  76. package/dist/validation/local.d.ts.map +1 -0
  77. package/dist/validation/local.js +290 -0
  78. package/dist/validation/local.js.map +1 -0
  79. package/dist/validation/papi.d.ts +6 -0
  80. package/dist/validation/papi.d.ts.map +1 -0
  81. package/dist/validation/papi.js +59 -0
  82. package/dist/validation/papi.js.map +1 -0
  83. package/package.json +55 -0
  84. package/src/skill/system-prompt.md +205 -0
  85. package/templates/.gitkeep +0 -0
  86. package/templates/CLAUDE.md +115 -0
  87. package/templates/copilot-instructions.md +78 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-configs.js","sourceRoot":"","sources":["../../src/tools/diff-configs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export interface GetPropertyConfigParams {
2
+ propertyId?: string;
3
+ version?: number;
4
+ repoPath?: string;
5
+ edgercPath?: string;
6
+ edgercSection?: string;
7
+ }
8
+ export declare function getPropertyConfig(params: GetPropertyConfigParams): Promise<string>;
9
+ //# sourceMappingURL=get-property-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-property-config.d.ts","sourceRoot":"","sources":["../../src/tools/get-property-config.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,uBAAuB;IACtC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,uBAAuB,GAAG,OAAO,CAAC,MAAM,CAAC,CAgCxF"}
@@ -0,0 +1,53 @@
1
+ import { readFile, writeFile } from 'node:fs/promises';
2
+ import { resolve } from 'node:path';
3
+ import { PapiClient } from '../papi/client.js';
4
+ import { resolveCredentials } from '../papi/auth.js';
5
+ import { findPmDirectory } from '../config/snippets.js';
6
+ export async function getPropertyConfig(params) {
7
+ const { version, edgercPath, edgercSection } = params;
8
+ let { propertyId } = params;
9
+ // Auto-detect propertyId from envInfo.json if repoPath provided
10
+ if (!propertyId && params.repoPath) {
11
+ propertyId = await detectPropertyId(params.repoPath);
12
+ }
13
+ if (!propertyId) {
14
+ throw new Error('Either propertyId or repoPath must be provided to identify the property');
15
+ }
16
+ const credentials = await resolveCredentials({ edgercPath, section: edgercSection });
17
+ const client = new PapiClient(credentials);
18
+ const ruleTree = await client.getRuleTree(propertyId, version);
19
+ // Best-effort: store the etag for future sync comparisons
20
+ if (params.repoPath && ruleTree.etag) {
21
+ try {
22
+ const pmDir = await findPmDirectory(params.repoPath);
23
+ const envInfoPath = resolve(pmDir, 'envInfo.json');
24
+ const envContent = await readFile(envInfoPath, 'utf-8');
25
+ const envInfo = JSON.parse(envContent);
26
+ envInfo.lastKnownRuleTreeEtag = ruleTree.etag;
27
+ await writeFile(envInfoPath, JSON.stringify(envInfo, null, 2) + '\n', 'utf-8');
28
+ }
29
+ catch {
30
+ // Don't fail the tool call if writing the etag fails
31
+ }
32
+ }
33
+ return JSON.stringify(ruleTree, null, 2);
34
+ }
35
+ async function detectPropertyId(repoPath) {
36
+ const pmDir = await findPmDirectory(repoPath);
37
+ const envInfoPath = resolve(pmDir, 'envInfo.json');
38
+ try {
39
+ const content = await readFile(envInfoPath, 'utf-8');
40
+ const envInfo = JSON.parse(content);
41
+ if (!envInfo.propertyId) {
42
+ throw new Error('propertyId field not found in envInfo.json');
43
+ }
44
+ return String(envInfo.propertyId);
45
+ }
46
+ catch (error) {
47
+ if (error.code === 'ENOENT') {
48
+ throw new Error(`envInfo.json not found at ${envInfoPath}`);
49
+ }
50
+ throw error;
51
+ }
52
+ }
53
+ //# sourceMappingURL=get-property-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-property-config.js","sourceRoot":"","sources":["../../src/tools/get-property-config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ export interface TriggerPipelineParams {
2
+ repoPath: string;
3
+ branch?: string;
4
+ variables?: Record<string, string>;
5
+ }
6
+ export declare function triggerPipeline(params: TriggerPipelineParams): Promise<{
7
+ url: string;
8
+ id: number | string;
9
+ provider: string;
10
+ }>;
11
+ //# sourceMappingURL=pipeline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/tools/pipeline.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC;AAED,wBAAsB,eAAe,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC;IAC5E,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC,CAMD"}
@@ -0,0 +1,9 @@
1
+ import { createProvider } from '../git/provider.js';
2
+ import { getCurrentBranch } from '../git/git-ops.js';
3
+ export async function triggerPipeline(params) {
4
+ const { repoPath, variables } = params;
5
+ const branch = params.branch ?? await getCurrentBranch(repoPath);
6
+ const provider = await createProvider(repoPath);
7
+ return provider.triggerPipeline({ branch, variables });
8
+ }
9
+ //# sourceMappingURL=pipeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../../src/tools/pipeline.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAQrD,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,MAA6B;IAKjE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC;IACvC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,MAAM,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IACjE,MAAM,QAAQ,GAAG,MAAM,cAAc,CAAC,QAAQ,CAAC,CAAC;IAEhD,OAAO,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;AACzD,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { SyncResult } from '../papi/types.js';
2
+ export interface SyncPropertyParams {
3
+ repoPath: string;
4
+ dryRun?: boolean;
5
+ edgercPath?: string;
6
+ edgercSection?: string;
7
+ }
8
+ export declare function syncProperty(params: SyncPropertyParams): Promise<SyncResult>;
9
+ //# sourceMappingURL=sync-property.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-property.d.ts","sourceRoot":"","sources":["../../src/tools/sync-property.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAW,UAAU,EAAc,MAAM,kBAAkB,CAAC;AAExE,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,wBAAsB,YAAY,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,UAAU,CAAC,CA8DlF"}
@@ -0,0 +1,65 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { resolve } from 'node:path';
3
+ import { PapiClient } from '../papi/client.js';
4
+ import { resolveCredentials } from '../papi/auth.js';
5
+ import { findPmDirectory } from '../config/snippets.js';
6
+ export async function syncProperty(params) {
7
+ const { repoPath, edgercPath, edgercSection } = params;
8
+ // Read local envInfo
9
+ const pmDir = await findPmDirectory(repoPath);
10
+ const envInfoPath = resolve(pmDir, 'envInfo.json');
11
+ let envInfo;
12
+ try {
13
+ const content = await readFile(envInfoPath, 'utf-8');
14
+ envInfo = JSON.parse(content);
15
+ }
16
+ catch (error) {
17
+ if (error.code === 'ENOENT') {
18
+ throw new Error(`envInfo.json not found at ${envInfoPath}`);
19
+ }
20
+ throw error;
21
+ }
22
+ // Fetch remote version info
23
+ const credentials = await resolveCredentials({ edgercPath, section: edgercSection });
24
+ const client = new PapiClient(credentials);
25
+ const propertyId = String(envInfo.propertyId);
26
+ const versions = await client.getPropertyVersions(propertyId);
27
+ if (versions.length === 0) {
28
+ throw new Error(`No versions found for property ${propertyId}`);
29
+ }
30
+ // Get latest remote version
31
+ const sorted = [...versions].sort((a, b) => b.propertyVersion - a.propertyVersion);
32
+ const latestRemote = sorted[0];
33
+ // Determine sync status by version number comparison
34
+ const localVersion = envInfo.latestVersionInfo.propertyVersion;
35
+ let status;
36
+ let localEtag;
37
+ let remoteEtag;
38
+ if (localVersion === latestRemote.propertyVersion) {
39
+ // Same version — check for content drift via etag comparison
40
+ localEtag = envInfo.lastKnownRuleTreeEtag;
41
+ if (localEtag) {
42
+ const remoteRuleTree = await client.getRuleTree(propertyId, latestRemote.propertyVersion);
43
+ remoteEtag = remoteRuleTree.etag;
44
+ status = localEtag === remoteEtag ? 'in-sync' : 'content-modified';
45
+ }
46
+ else {
47
+ // No local etag stored — can't compare, assume OK
48
+ status = 'in-sync';
49
+ }
50
+ }
51
+ else if (localVersion < latestRemote.propertyVersion) {
52
+ status = 'remote-ahead';
53
+ }
54
+ else {
55
+ status = 'local-ahead';
56
+ }
57
+ return {
58
+ status,
59
+ localVersion,
60
+ remoteVersion: latestRemote.propertyVersion,
61
+ localEtag,
62
+ remoteEtag,
63
+ };
64
+ }
65
+ //# sourceMappingURL=sync-property.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-property.js","sourceRoot":"","sources":["../../src/tools/sync-property.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import type { PapiRule } from '../papi/types.js';
2
+ export interface WriteSnippetParams {
3
+ repoPath: string;
4
+ snippetName: string;
5
+ content: string;
6
+ addToMainJson?: boolean;
7
+ position?: 'beginning' | 'end';
8
+ }
9
+ export interface WriteSnippetResult {
10
+ success: boolean;
11
+ path: string;
12
+ addedToMain: boolean;
13
+ }
14
+ export declare function writeSnippet(params: WriteSnippetParams): Promise<WriteSnippetResult>;
15
+ export interface ApplyBehaviorParams {
16
+ repoPath: string;
17
+ snippetName: string;
18
+ behavior: string;
19
+ criteria?: string;
20
+ criteriaMustSatisfy?: 'all' | 'any';
21
+ }
22
+ export interface ApplyBehaviorResult {
23
+ success: boolean;
24
+ action: 'added' | 'replaced';
25
+ snippetPath: string;
26
+ before: PapiRule;
27
+ after: PapiRule;
28
+ }
29
+ export declare function applyBehavior(params: ApplyBehaviorParams): Promise<ApplyBehaviorResult>;
30
+ //# sourceMappingURL=write-snippet.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write-snippet.d.ts","sourceRoot":"","sources":["../../src/tools/write-snippet.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAgB,MAAM,kBAAkB,CAAC;AAK/D,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,WAAW,GAAG,KAAK,CAAC;CAChC;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,wBAAsB,YAAY,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAiD1F;AAID,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mBAAmB,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC;CACrC;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,GAAG,UAAU,CAAC;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,QAAQ,CAAC;IACjB,KAAK,EAAE,QAAQ,CAAC;CACjB;AAED,wBAAsB,aAAa,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAiD7F"}
@@ -0,0 +1,92 @@
1
+ import { writeFile } from 'node:fs/promises';
2
+ import { resolve } from 'node:path';
3
+ import { findPmDirectory, readSnippet } from '../config/snippets.js';
4
+ import { readFile } from 'node:fs/promises';
5
+ const REQUIRED_FIELDS = ['name', 'children', 'behaviors', 'criteria', 'criteriaMustSatisfy'];
6
+ export async function writeSnippet(params) {
7
+ const { repoPath, snippetName, content, addToMainJson = false, position = 'end' } = params;
8
+ // Parse and validate content
9
+ let rule;
10
+ try {
11
+ rule = JSON.parse(content);
12
+ }
13
+ catch {
14
+ throw new Error(`Invalid JSON in snippet content: ${content.slice(0, 100)}...`);
15
+ }
16
+ // Validate required PapiRule fields
17
+ for (const field of REQUIRED_FIELDS) {
18
+ if (!(field in rule)) {
19
+ throw new Error(`Missing required field '${field}' in snippet content`);
20
+ }
21
+ }
22
+ // Write snippet file
23
+ const pmDir = await findPmDirectory(repoPath);
24
+ const snippetPath = resolve(pmDir, 'config-snippets', snippetName);
25
+ await writeFile(snippetPath, JSON.stringify(rule, null, 2) + '\n', 'utf-8');
26
+ // Optionally add #include: to main.json
27
+ let addedToMain = false;
28
+ if (addToMainJson) {
29
+ const mainPath = resolve(pmDir, 'config-snippets', 'main.json');
30
+ const mainContent = await readFile(mainPath, 'utf-8');
31
+ const main = JSON.parse(mainContent);
32
+ const includeDirective = `#include:${snippetName}`;
33
+ // Check if already included
34
+ const alreadyIncluded = main.rules.children.some(c => typeof c === 'string' && c === includeDirective);
35
+ if (!alreadyIncluded) {
36
+ if (position === 'beginning') {
37
+ main.rules.children.unshift(includeDirective);
38
+ }
39
+ else {
40
+ main.rules.children.push(includeDirective);
41
+ }
42
+ await writeFile(mainPath, JSON.stringify(main, null, 2) + '\n', 'utf-8');
43
+ addedToMain = true;
44
+ }
45
+ }
46
+ return { success: true, path: snippetPath, addedToMain };
47
+ }
48
+ export async function applyBehavior(params) {
49
+ const { repoPath, snippetName, criteriaMustSatisfy } = params;
50
+ // Parse behavior
51
+ let behavior;
52
+ try {
53
+ behavior = JSON.parse(params.behavior);
54
+ }
55
+ catch {
56
+ throw new Error('Invalid JSON in behavior parameter');
57
+ }
58
+ // Read existing snippet
59
+ const snippet = await readSnippet(repoPath, snippetName);
60
+ const before = structuredClone(snippet);
61
+ // Find existing behavior by name
62
+ const existingIdx = snippet.behaviors.findIndex(b => b.name === behavior.name);
63
+ let action;
64
+ if (existingIdx >= 0) {
65
+ // Replace in-place
66
+ snippet.behaviors[existingIdx] = behavior;
67
+ action = 'replaced';
68
+ }
69
+ else {
70
+ // Append
71
+ snippet.behaviors.push(behavior);
72
+ action = 'added';
73
+ }
74
+ // Optionally update criteria
75
+ if (params.criteria) {
76
+ snippet.criteria = JSON.parse(params.criteria);
77
+ }
78
+ if (criteriaMustSatisfy) {
79
+ snippet.criteriaMustSatisfy = criteriaMustSatisfy;
80
+ }
81
+ // Validate and write
82
+ for (const field of REQUIRED_FIELDS) {
83
+ if (!(field in snippet)) {
84
+ throw new Error(`Modified snippet missing required field '${field}'`);
85
+ }
86
+ }
87
+ const pmDir = await findPmDirectory(repoPath);
88
+ const snippetPath = resolve(pmDir, 'config-snippets', snippetName);
89
+ await writeFile(snippetPath, JSON.stringify(snippet, null, 2) + '\n', 'utf-8');
90
+ return { success: true, action, snippetPath, before, after: snippet };
91
+ }
92
+ //# sourceMappingURL=write-snippet.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write-snippet.js","sourceRoot":"","sources":["../../src/tools/write-snippet.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { ValidationResult } from '../papi/types.js';
2
+ export declare function validateLocal(repoPath: string): Promise<ValidationResult>;
3
+ //# sourceMappingURL=local.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../src/validation/local.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAA6B,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEpF,wBAAsB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAqB/E"}
@@ -0,0 +1,290 @@
1
+ import { readFile, readdir } from 'node:fs/promises';
2
+ import { resolve } from 'node:path';
3
+ import { findPmDirectory } from '../config/snippets.js';
4
+ export async function validateLocal(repoPath) {
5
+ const pmDir = await findPmDirectory(repoPath);
6
+ const snippetsDir = resolve(pmDir, 'config-snippets');
7
+ const checks = [];
8
+ // Run all 7 checks independently
9
+ checks.push(...await checkJsonSyntax(snippetsDir));
10
+ checks.push(...await checkRequiredFields(snippetsDir));
11
+ checks.push(...await checkIncludeResolution(snippetsDir));
12
+ checks.push(...await checkOrphans(snippetsDir));
13
+ checks.push(...await checkVariableReferences(snippetsDir, pmDir));
14
+ checks.push(...await checkDuplicateRuleNames(snippetsDir));
15
+ checks.push(...await checkNoopRules(snippetsDir));
16
+ return {
17
+ valid: checks.filter(c => c.severity === 'error').length === 0,
18
+ errors: checks.filter(c => c.severity === 'error'),
19
+ warnings: checks.filter(c => c.severity === 'warning'),
20
+ infos: checks.filter(c => c.severity === 'info'),
21
+ };
22
+ }
23
+ // Check 1: JSON syntax — every .json in config-snippets/ must parse (severity: error)
24
+ async function checkJsonSyntax(snippetsDir) {
25
+ const checks = [];
26
+ const files = await readdir(snippetsDir);
27
+ for (const file of files) {
28
+ if (!file.endsWith('.json'))
29
+ continue;
30
+ try {
31
+ const content = await readFile(resolve(snippetsDir, file), 'utf-8');
32
+ JSON.parse(content);
33
+ }
34
+ catch (e) {
35
+ checks.push({
36
+ check: 'json-syntax',
37
+ severity: 'error',
38
+ message: `Invalid JSON in ${file}: ${e.message}`,
39
+ location: file,
40
+ });
41
+ }
42
+ }
43
+ return checks;
44
+ }
45
+ // Check 2: Required fields — each rule must have: name, children, behaviors, criteria, criteriaMustSatisfy (severity: error)
46
+ async function checkRequiredFields(snippetsDir) {
47
+ const checks = [];
48
+ const required = ['name', 'children', 'behaviors', 'criteria', 'criteriaMustSatisfy'];
49
+ const files = await readdir(snippetsDir);
50
+ for (const file of files) {
51
+ if (!file.endsWith('.json'))
52
+ continue;
53
+ try {
54
+ const content = await readFile(resolve(snippetsDir, file), 'utf-8');
55
+ const parsed = JSON.parse(content);
56
+ // main.json has { rules: { ... } } envelope
57
+ const rule = file === 'main.json' ? parsed.rules : parsed;
58
+ if (!rule)
59
+ continue;
60
+ const checkRule = (r, path) => {
61
+ for (const field of required) {
62
+ if (!(field in r)) {
63
+ checks.push({
64
+ check: 'required-fields',
65
+ severity: 'error',
66
+ message: `Missing required field '${field}' in ${path}`,
67
+ location: `${file}:${path}`,
68
+ });
69
+ }
70
+ }
71
+ // Check children recursively (but only actual objects, not #include strings)
72
+ if (Array.isArray(r['children'])) {
73
+ for (const child of r['children']) {
74
+ if (typeof child === 'object' && child !== null) {
75
+ checkRule(child, `${path} > ${child.name ?? 'unnamed'}`);
76
+ }
77
+ }
78
+ }
79
+ };
80
+ checkRule(rule, rule.name ?? file);
81
+ }
82
+ catch {
83
+ // JSON syntax errors handled by check 1
84
+ }
85
+ }
86
+ return checks;
87
+ }
88
+ // Check 3: Include resolution — every #include: in main.json references an existing file (severity: error)
89
+ async function checkIncludeResolution(snippetsDir) {
90
+ const checks = [];
91
+ try {
92
+ const mainContent = await readFile(resolve(snippetsDir, 'main.json'), 'utf-8');
93
+ const main = JSON.parse(mainContent);
94
+ const rules = main.rules;
95
+ if (!rules?.children)
96
+ return checks;
97
+ const files = await readdir(snippetsDir);
98
+ const checkIncludes = (children, path) => {
99
+ for (const child of children) {
100
+ if (typeof child === 'string' && child.startsWith('#include:')) {
101
+ const filename = child.slice('#include:'.length);
102
+ if (!files.includes(filename)) {
103
+ checks.push({
104
+ check: 'include-resolution',
105
+ severity: 'error',
106
+ message: `Include target not found: ${filename}`,
107
+ location: `main.json:${path}`,
108
+ });
109
+ }
110
+ }
111
+ }
112
+ };
113
+ checkIncludes(rules.children, 'default');
114
+ }
115
+ catch {
116
+ // No main.json or parse error — handled by other checks
117
+ }
118
+ return checks;
119
+ }
120
+ // Check 4: Orphan detection — snippets not referenced by any #include: (severity: warning)
121
+ async function checkOrphans(snippetsDir) {
122
+ const checks = [];
123
+ try {
124
+ const mainContent = await readFile(resolve(snippetsDir, 'main.json'), 'utf-8');
125
+ const main = JSON.parse(mainContent);
126
+ const rules = main.rules;
127
+ // Collect all referenced includes
128
+ const referenced = new Set();
129
+ const collectIncludes = (children) => {
130
+ for (const child of children) {
131
+ if (typeof child === 'string' && child.startsWith('#include:')) {
132
+ referenced.add(child.slice('#include:'.length));
133
+ }
134
+ }
135
+ };
136
+ if (rules?.children)
137
+ collectIncludes(rules.children);
138
+ // Check all snippet files
139
+ const files = await readdir(snippetsDir);
140
+ for (const file of files) {
141
+ if (file === 'main.json' || !file.endsWith('.json'))
142
+ continue;
143
+ if (!referenced.has(file)) {
144
+ checks.push({
145
+ check: 'orphan-detection',
146
+ severity: 'warning',
147
+ message: `Snippet '${file}' is not referenced by any #include: directive`,
148
+ location: file,
149
+ });
150
+ }
151
+ }
152
+ }
153
+ catch {
154
+ // Handled elsewhere
155
+ }
156
+ return checks;
157
+ }
158
+ // Check 5: Variable references — {{user.PMUSER_*}} patterns must match declared variables (severity: warning)
159
+ async function checkVariableReferences(snippetsDir, _pmDir) {
160
+ const checks = [];
161
+ try {
162
+ // Get declared variables from main.json
163
+ const mainContent = await readFile(resolve(snippetsDir, 'main.json'), 'utf-8');
164
+ const main = JSON.parse(mainContent);
165
+ const declaredVars = new Set();
166
+ if (main.rules?.variables) {
167
+ for (const v of main.rules.variables) {
168
+ declaredVars.add(v.name);
169
+ }
170
+ }
171
+ // Scan all snippet files for variable references
172
+ const files = await readdir(snippetsDir);
173
+ for (const file of files) {
174
+ if (!file.endsWith('.json'))
175
+ continue;
176
+ const content = await readFile(resolve(snippetsDir, file), 'utf-8');
177
+ const refs = content.match(/\{\{user\.(PMUSER_\w+)\}\}/g);
178
+ if (!refs)
179
+ continue;
180
+ for (const ref of refs) {
181
+ const varName = ref.match(/\{\{user\.(\w+)\}\}/)[1];
182
+ if (!declaredVars.has(varName)) {
183
+ checks.push({
184
+ check: 'variable-references',
185
+ severity: 'warning',
186
+ message: `Variable '${varName}' referenced in ${file} but not declared in main.json variables`,
187
+ location: file,
188
+ });
189
+ }
190
+ }
191
+ }
192
+ }
193
+ catch {
194
+ // Handled elsewhere
195
+ }
196
+ return checks;
197
+ }
198
+ // Check 6: Duplicate rule names — sibling rules with same name (severity: warning)
199
+ async function checkDuplicateRuleNames(snippetsDir) {
200
+ const checks = [];
201
+ const files = await readdir(snippetsDir);
202
+ for (const file of files) {
203
+ if (!file.endsWith('.json'))
204
+ continue;
205
+ try {
206
+ const content = await readFile(resolve(snippetsDir, file), 'utf-8');
207
+ const parsed = JSON.parse(content);
208
+ const rule = file === 'main.json' ? parsed.rules : parsed;
209
+ if (!rule)
210
+ continue;
211
+ const checkChildren = (r, path) => {
212
+ if (!Array.isArray(r.children))
213
+ return;
214
+ const names = new Map();
215
+ for (const child of r.children) {
216
+ if (typeof child === 'object' && child !== null) {
217
+ const name = child.name;
218
+ if (name) {
219
+ names.set(name, (names.get(name) ?? 0) + 1);
220
+ }
221
+ }
222
+ }
223
+ for (const [name, count] of names) {
224
+ if (count > 1) {
225
+ checks.push({
226
+ check: 'duplicate-rule-names',
227
+ severity: 'warning',
228
+ message: `Duplicate rule name '${name}' (${count} occurrences) under ${path}`,
229
+ location: `${file}:${path}`,
230
+ });
231
+ }
232
+ }
233
+ // Recurse
234
+ for (const child of r.children) {
235
+ if (typeof child === 'object' && child !== null) {
236
+ checkChildren(child, `${path} > ${child.name ?? 'unnamed'}`);
237
+ }
238
+ }
239
+ };
240
+ checkChildren(rule, rule.name ?? file);
241
+ }
242
+ catch {
243
+ // Handled by syntax check
244
+ }
245
+ }
246
+ return checks;
247
+ }
248
+ // Check 7: No-op rules — rules with empty behaviors, criteria, AND children (severity: info)
249
+ async function checkNoopRules(snippetsDir) {
250
+ const checks = [];
251
+ const files = await readdir(snippetsDir);
252
+ for (const file of files) {
253
+ if (!file.endsWith('.json'))
254
+ continue;
255
+ try {
256
+ const content = await readFile(resolve(snippetsDir, file), 'utf-8');
257
+ const parsed = JSON.parse(content);
258
+ const rule = file === 'main.json' ? parsed.rules : parsed;
259
+ if (!rule)
260
+ continue;
261
+ const checkNoop = (r, path) => {
262
+ const hasNoBehaviors = !r.behaviors || r.behaviors.length === 0;
263
+ const hasNoCriteria = !r.criteria || r.criteria.length === 0;
264
+ const hasNoChildren = !r.children || r.children.length === 0;
265
+ if (hasNoBehaviors && hasNoCriteria && hasNoChildren) {
266
+ checks.push({
267
+ check: 'noop-rules',
268
+ severity: 'info',
269
+ message: `Rule '${r.name}' has no behaviors, criteria, or children`,
270
+ location: `${file}:${path}`,
271
+ });
272
+ }
273
+ // Recurse into children
274
+ if (Array.isArray(r.children)) {
275
+ for (const child of r.children) {
276
+ if (typeof child === 'object' && child !== null) {
277
+ checkNoop(child, `${path} > ${child.name}`);
278
+ }
279
+ }
280
+ }
281
+ };
282
+ checkNoop(rule, rule.name ?? file);
283
+ }
284
+ catch {
285
+ // Handled by syntax check
286
+ }
287
+ }
288
+ return checks;
289
+ }
290
+ //# sourceMappingURL=local.js.map