@veewo/gitnexus 1.5.6 → 1.5.8

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 (104) hide show
  1. package/dist/benchmark/analyze-runner.d.ts +0 -2
  2. package/dist/benchmark/analyze-runner.js +0 -6
  3. package/dist/benchmark/analyze-runner.test.js +1 -10
  4. package/dist/benchmark/runner.d.ts +0 -2
  5. package/dist/benchmark/runner.js +0 -2
  6. package/dist/benchmark/u2-e2e/neonspark-full-e2e.js +0 -11
  7. package/dist/benchmark/u2-performance-sampler.js +3 -16
  8. package/dist/cli/ai-context.js +1 -7
  9. package/dist/cli/analyze-options.d.ts +19 -6
  10. package/dist/cli/analyze-options.js +76 -71
  11. package/dist/cli/analyze-options.test.js +78 -73
  12. package/dist/cli/analyze-runtime-summary.js +0 -1
  13. package/dist/cli/analyze-runtime-summary.test.js +0 -2
  14. package/dist/cli/analyze-summary.d.ts +0 -2
  15. package/dist/cli/analyze-summary.js +0 -24
  16. package/dist/cli/analyze-summary.test.js +1 -65
  17. package/dist/cli/analyze.d.ts +2 -4
  18. package/dist/cli/analyze.js +14 -30
  19. package/dist/cli/analyze.test.js +9 -15
  20. package/dist/cli/benchmark-agent-context.d.ts +0 -2
  21. package/dist/cli/benchmark-agent-context.js +0 -2
  22. package/dist/cli/benchmark-agent-safe-query-context.d.ts +0 -2
  23. package/dist/cli/benchmark-agent-safe-query-context.js +0 -2
  24. package/dist/cli/benchmark-unity.d.ts +0 -2
  25. package/dist/cli/benchmark-unity.js +0 -2
  26. package/dist/cli/clean.d.ts +2 -3
  27. package/dist/cli/clean.js +4 -25
  28. package/dist/cli/index.js +1 -12
  29. package/dist/core/ingestion/pipeline.js +1 -44
  30. package/dist/mcp/local/agent-safe-response.js +1 -1
  31. package/dist/mcp/local/local-backend.d.ts +0 -23
  32. package/dist/mcp/local/local-backend.js +69 -248
  33. package/dist/mcp/local/runtime-chain-verify.test.js +0 -49
  34. package/dist/mcp/local/runtime-claim-rule-registry.d.ts +0 -11
  35. package/dist/mcp/local/runtime-claim-rule-registry.js +0 -159
  36. package/dist/mcp/local/runtime-claim-rule-registry.test.js +67 -214
  37. package/dist/mcp/tools.js +0 -70
  38. package/dist/storage/repo-manager.d.ts +1 -0
  39. package/dist/types/pipeline.d.ts +0 -3
  40. package/package.json +1 -1
  41. package/skills/gitnexus-cli.md +62 -38
  42. package/vendor/node_modules/node-addon-api/node_addon_api.Makefile +6 -0
  43. package/vendor/node_modules/node-addon-api/node_addon_api.target.mk +122 -0
  44. package/vendor/node_modules/node-addon-api/node_addon_api_except.target.mk +126 -0
  45. package/vendor/node_modules/node-addon-api/node_addon_api_except_all.target.mk +122 -0
  46. package/vendor/node_modules/node-addon-api/node_addon_api_maybe.target.mk +122 -0
  47. package/vendor/tree-sitter-dart/build/Release/.deps/node_modules/node-addon-api/node_addon_api_except.stamp.d +1 -0
  48. package/vendor/tree-sitter-dart/build/node_modules/node-addon-api/node_addon_api_except.stamp +0 -0
  49. package/vendor/tree-sitter-proto/build/Release/.deps/node_modules/node-addon-api/node_addon_api_except.stamp.d +1 -0
  50. package/vendor/tree-sitter-proto/build/node_modules/node-addon-api/node_addon_api_except.stamp +0 -0
  51. package/dist/benchmark/u2-e2e/phase5-rule-lab-acceptance-runner.d.ts +0 -60
  52. package/dist/benchmark/u2-e2e/phase5-rule-lab-acceptance-runner.js +0 -395
  53. package/dist/benchmark/u2-e2e/phase5-rule-lab-acceptance-runner.test.d.ts +0 -1
  54. package/dist/benchmark/u2-e2e/phase5-rule-lab-acceptance-runner.test.js +0 -41
  55. package/dist/cli/rule-lab.d.ts +0 -38
  56. package/dist/cli/rule-lab.js +0 -148
  57. package/dist/cli/rule-lab.test.d.ts +0 -1
  58. package/dist/cli/rule-lab.test.js +0 -31
  59. package/dist/cli/scope-manifest-config.d.ts +0 -9
  60. package/dist/cli/scope-manifest-config.js +0 -37
  61. package/dist/cli/sync-manifest.d.ts +0 -27
  62. package/dist/cli/sync-manifest.js +0 -200
  63. package/dist/cli/sync-manifest.test.d.ts +0 -1
  64. package/dist/cli/sync-manifest.test.js +0 -88
  65. package/dist/core/ingestion/unity-runtime-binding-rules.d.ts +0 -26
  66. package/dist/core/ingestion/unity-runtime-binding-rules.js +0 -408
  67. package/dist/rule-lab/analyze.d.ts +0 -13
  68. package/dist/rule-lab/analyze.js +0 -125
  69. package/dist/rule-lab/analyze.test.d.ts +0 -1
  70. package/dist/rule-lab/analyze.test.js +0 -246
  71. package/dist/rule-lab/compile.d.ts +0 -5
  72. package/dist/rule-lab/compile.js +0 -51
  73. package/dist/rule-lab/compiled-bundles.d.ts +0 -30
  74. package/dist/rule-lab/compiled-bundles.js +0 -36
  75. package/dist/rule-lab/curate.d.ts +0 -33
  76. package/dist/rule-lab/curate.js +0 -155
  77. package/dist/rule-lab/curate.test.d.ts +0 -1
  78. package/dist/rule-lab/curate.test.js +0 -137
  79. package/dist/rule-lab/curation-input-builder.d.ts +0 -45
  80. package/dist/rule-lab/curation-input-builder.js +0 -133
  81. package/dist/rule-lab/discover.d.ts +0 -13
  82. package/dist/rule-lab/discover.js +0 -74
  83. package/dist/rule-lab/discover.test.d.ts +0 -1
  84. package/dist/rule-lab/discover.test.js +0 -42
  85. package/dist/rule-lab/paths.d.ts +0 -21
  86. package/dist/rule-lab/paths.js +0 -37
  87. package/dist/rule-lab/paths.test.d.ts +0 -1
  88. package/dist/rule-lab/paths.test.js +0 -46
  89. package/dist/rule-lab/promote.d.ts +0 -26
  90. package/dist/rule-lab/promote.js +0 -387
  91. package/dist/rule-lab/promote.test.d.ts +0 -1
  92. package/dist/rule-lab/promote.test.js +0 -314
  93. package/dist/rule-lab/regress.d.ts +0 -60
  94. package/dist/rule-lab/regress.js +0 -122
  95. package/dist/rule-lab/regress.test.d.ts +0 -1
  96. package/dist/rule-lab/regress.test.js +0 -68
  97. package/dist/rule-lab/review-pack.d.ts +0 -34
  98. package/dist/rule-lab/review-pack.js +0 -165
  99. package/dist/rule-lab/review-pack.test.d.ts +0 -1
  100. package/dist/rule-lab/review-pack.test.js +0 -116
  101. package/dist/rule-lab/types.d.ts +0 -135
  102. package/dist/rule-lab/types.js +0 -1
  103. package/skills/_shared/unity-rule-authoring-contract.md +0 -64
  104. package/skills/gitnexus-unity-rule-gen.md +0 -107
@@ -1,246 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import fs from 'node:fs/promises';
3
- import os from 'node:os';
4
- import path from 'node:path';
5
- import { analyzeRuleLabSlice } from './analyze.js';
6
- import { curateRuleLabSlice } from './curate.js';
7
- import { promoteCuratedRules } from './promote.js';
8
- async function writeJson(filePath, value) {
9
- await fs.mkdir(path.dirname(filePath), { recursive: true });
10
- await fs.writeFile(filePath, `${JSON.stringify(value, null, 2)}\n`, 'utf-8');
11
- }
12
- describe('rule-lab analyze (exact pair flow)', () => {
13
- it('builds proposal candidates and curation input directly from exact_pairs', async () => {
14
- const repoRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'rule-lab-analyze-exact-'));
15
- const runId = 'run-x';
16
- const sliceId = 'slice-a';
17
- const slicePath = path.join(repoRoot, '.gitnexus', 'rules', 'lab', 'runs', runId, 'slices', sliceId, 'slice.json');
18
- await writeJson(slicePath, {
19
- id: sliceId,
20
- trigger_family: 'event_delegate',
21
- resource_types: ['syncvar_hook'],
22
- host_base_type: ['network_behaviour'],
23
- required_hops: ['code_runtime'],
24
- exact_pairs: [
25
- {
26
- id: 'pair-a',
27
- binding_kind: 'method_triggers_method',
28
- source_anchor: { file: 'Assets/Gameplay/SourceA.cs', line: 12, symbol: 'SourceA.Trigger' },
29
- target_anchor: { file: 'Assets/Gameplay/TargetA.cs', line: 32, symbol: 'TargetA.OnTrigger' },
30
- },
31
- {
32
- id: 'pair-b',
33
- binding_kind: 'method_triggers_method',
34
- source_anchor: { file: 'Assets/Gameplay/SourceB.cs', line: 15, symbol: 'SourceB.Trigger' },
35
- target_anchor: { file: 'Assets/Gameplay/TargetB.cs', line: 36, symbol: 'TargetB.OnTrigger' },
36
- },
37
- ],
38
- });
39
- const out = await analyzeRuleLabSlice({ repoPath: repoRoot, runId, sliceId });
40
- expect(out.candidates).toHaveLength(2);
41
- expect(out.candidates.every((candidate) => candidate.proposal_kind === 'per_anchor_rule')).toBe(true);
42
- expect(out.candidates.every((candidate) => candidate.exact_pair)).toBe(true);
43
- const curationPath = path.join(path.dirname(out.paths.candidatesPath), 'curation-input.json');
44
- const curation = JSON.parse(await fs.readFile(curationPath, 'utf-8'));
45
- expect(curation.curated).toHaveLength(2);
46
- expect(curation.curated.every((item) => item.confirmed_chain.steps.length > 0)).toBe(true);
47
- expect(curation.curated.every((item) => Array.isArray(item.resource_bindings) && item.resource_bindings.length > 0)).toBe(true);
48
- await fs.rm(repoRoot, { recursive: true, force: true });
49
- });
50
- it('fails when exact_pairs are missing', async () => {
51
- const repoRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'rule-lab-analyze-exact-missing-'));
52
- const runId = 'run-x';
53
- const sliceId = 'slice-a';
54
- const slicePath = path.join(repoRoot, '.gitnexus', 'rules', 'lab', 'runs', runId, 'slices', sliceId, 'slice.json');
55
- await writeJson(slicePath, {
56
- id: sliceId,
57
- trigger_family: 'event_delegate',
58
- resource_types: ['syncvar_hook'],
59
- host_base_type: ['network_behaviour'],
60
- required_hops: ['code_runtime'],
61
- });
62
- await expect(analyzeRuleLabSlice({ repoPath: repoRoot, runId, sliceId })).rejects.toThrow(/exact_pairs/i);
63
- await fs.rm(repoRoot, { recursive: true, force: true });
64
- });
65
- it('fails fast when exact_pairs contain duplicate non-empty ids', async () => {
66
- const repoRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'rule-lab-analyze-exact-dup-id-'));
67
- const runId = 'run-x';
68
- const sliceId = 'slice-a';
69
- const slicePath = path.join(repoRoot, '.gitnexus', 'rules', 'lab', 'runs', runId, 'slices', sliceId, 'slice.json');
70
- await writeJson(slicePath, {
71
- id: sliceId,
72
- trigger_family: 'event_delegate',
73
- resource_types: ['syncvar_hook'],
74
- host_base_type: ['network_behaviour'],
75
- required_hops: ['code_runtime'],
76
- exact_pairs: [
77
- {
78
- id: 'pair-dup',
79
- binding_kind: 'method_triggers_method',
80
- source_anchor: { file: 'Assets/Gameplay/SourceA.cs', line: 12, symbol: 'SourceA.Trigger' },
81
- target_anchor: { file: 'Assets/Gameplay/TargetA.cs', line: 32, symbol: 'TargetA.OnTrigger' },
82
- },
83
- {
84
- id: 'pair-dup',
85
- binding_kind: 'method_triggers_method',
86
- source_anchor: { file: 'Assets/Gameplay/SourceB.cs', line: 15, symbol: 'SourceB.Trigger' },
87
- target_anchor: { file: 'Assets/Gameplay/TargetB.cs', line: 36, symbol: 'TargetB.OnTrigger' },
88
- },
89
- ],
90
- });
91
- await expect(analyzeRuleLabSlice({ repoPath: repoRoot, runId, sliceId })).rejects.toThrow(/duplicate_exact_pair_id/i);
92
- await fs.rm(repoRoot, { recursive: true, force: true });
93
- });
94
- it('supports exact-pair analyze -> curate -> promote flow', async () => {
95
- const repoRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'rule-lab-analyze-exact-e2e-'));
96
- const runId = 'run-x';
97
- const sliceId = 'slice-a';
98
- const sliceDir = path.join(repoRoot, '.gitnexus', 'rules', 'lab', 'runs', runId, 'slices', sliceId);
99
- const rulesRoot = path.join(repoRoot, '.gitnexus', 'rules');
100
- const slicePath = path.join(sliceDir, 'slice.json');
101
- await fs.mkdir(path.join(rulesRoot, 'approved'), { recursive: true });
102
- await fs.writeFile(path.join(rulesRoot, 'catalog.json'), JSON.stringify({ version: 1, rules: [] }, null, 2), 'utf-8');
103
- await writeJson(slicePath, {
104
- id: sliceId,
105
- trigger_family: 'event_delegate',
106
- resource_types: ['syncvar_hook'],
107
- host_base_type: ['network_behaviour'],
108
- required_hops: ['code_runtime'],
109
- exact_pairs: [
110
- {
111
- id: 'pair-a',
112
- binding_kind: 'method_triggers_method',
113
- source_anchor: { file: 'Assets/Gameplay/SourceA.cs', line: 12, symbol: 'SourceA.Trigger' },
114
- target_anchor: { file: 'Assets/Gameplay/TargetA.cs', line: 32, symbol: 'TargetA.OnTrigger' },
115
- },
116
- ],
117
- });
118
- const analyzed = await analyzeRuleLabSlice({ repoPath: repoRoot, runId, sliceId });
119
- const inputPath = path.join(path.dirname(analyzed.paths.candidatesPath), 'curation-input.json');
120
- await curateRuleLabSlice({ repoPath: repoRoot, runId, sliceId, inputPath });
121
- const promoted = await promoteCuratedRules({ repoPath: repoRoot, runId, sliceId, version: '1.0.0' });
122
- expect(promoted.promotedFiles).toHaveLength(1);
123
- await expect(fs.access(promoted.promotedFiles[0])).resolves.toBeUndefined();
124
- await fs.rm(repoRoot, { recursive: true, force: true });
125
- });
126
- it('fails closed when exact-pair symbols cannot resolve Class.Method', async () => {
127
- const repoRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'rule-lab-analyze-exact-unresolved-'));
128
- const runId = 'run-x';
129
- const sliceId = 'slice-a';
130
- const slicePath = path.join(repoRoot, '.gitnexus', 'rules', 'lab', 'runs', runId, 'slices', sliceId, 'slice.json');
131
- await writeJson(slicePath, {
132
- id: sliceId,
133
- trigger_family: 'event_delegate',
134
- resource_types: ['syncvar_hook'],
135
- host_base_type: ['network_behaviour'],
136
- required_hops: ['code_runtime'],
137
- exact_pairs: [
138
- {
139
- id: 'pair-a',
140
- binding_kind: 'method_triggers_method',
141
- source_anchor: { file: 'Assets/Gameplay/SourceA.cs', line: 12, symbol: 'TriggerOnly' },
142
- target_anchor: { file: 'Assets/Gameplay/TargetA.cs', line: 32, symbol: 'TargetA.OnTrigger' },
143
- },
144
- ],
145
- });
146
- await expect(analyzeRuleLabSlice({ repoPath: repoRoot, runId, sliceId })).rejects.toThrow(/binding_unresolved/i);
147
- await fs.rm(repoRoot, { recursive: true, force: true });
148
- });
149
- it('builds scene_load binding with host_class_pattern + loader_methods + scene_name', async () => {
150
- const repoRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'rule-lab-analyze-scene-load-shape-'));
151
- const runId = 'run-x';
152
- const sliceId = 'slice-a';
153
- const slicePath = path.join(repoRoot, '.gitnexus', 'rules', 'lab', 'runs', runId, 'slices', sliceId, 'slice.json');
154
- await writeJson(slicePath, {
155
- id: sliceId,
156
- trigger_family: 'event_delegate',
157
- resource_types: ['scene'],
158
- host_base_type: ['network_behaviour'],
159
- required_hops: ['code_runtime'],
160
- exact_pairs: [
161
- {
162
- id: 'pair-scene',
163
- binding_kind: 'method_triggers_scene_load',
164
- source_anchor: { file: 'Assets/Gameplay/SourceA.cs', line: 12, symbol: 'SourceA.Trigger' },
165
- target_anchor: { file: 'Assets/Scenes/BattleScene.unity', line: 1, symbol: 'BattleScene' },
166
- },
167
- ],
168
- });
169
- const analyzed = await analyzeRuleLabSlice({ repoPath: repoRoot, runId, sliceId });
170
- const curationPath = path.join(path.dirname(analyzed.paths.candidatesPath), 'curation-input.json');
171
- const curation = JSON.parse(await fs.readFile(curationPath, 'utf-8'));
172
- const binding = curation.curated[0].resource_bindings[0];
173
- expect(binding.kind).toBe('method_triggers_scene_load');
174
- expect(binding.host_class_pattern).toBe('SourceA');
175
- expect(binding.loader_methods).toEqual(['Trigger']);
176
- expect(binding.scene_name).toBe('BattleScene');
177
- expect(binding.source_class_pattern).toBeUndefined();
178
- expect(binding.source_method).toBeUndefined();
179
- expect(binding.target_class_pattern).toBeUndefined();
180
- expect(binding.target_method).toBeUndefined();
181
- await fs.rm(repoRoot, { recursive: true, force: true });
182
- });
183
- it('fails closed for scene_load when target scene token is missing', async () => {
184
- const repoRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'rule-lab-analyze-scene-load-missing-scene-'));
185
- const runId = 'run-x';
186
- const sliceId = 'slice-a';
187
- const slicePath = path.join(repoRoot, '.gitnexus', 'rules', 'lab', 'runs', runId, 'slices', sliceId, 'slice.json');
188
- await writeJson(slicePath, {
189
- id: sliceId,
190
- trigger_family: 'event_delegate',
191
- resource_types: ['scene'],
192
- host_base_type: ['network_behaviour'],
193
- required_hops: ['code_runtime'],
194
- exact_pairs: [
195
- {
196
- id: 'pair-scene',
197
- binding_kind: 'method_triggers_scene_load',
198
- source_anchor: { file: 'Assets/Gameplay/SourceA.cs', line: 12, symbol: 'SourceA.Trigger' },
199
- target_anchor: { file: '', line: 1, symbol: '' },
200
- },
201
- ],
202
- });
203
- await expect(analyzeRuleLabSlice({ repoPath: repoRoot, runId, sliceId })).rejects.toThrow(/binding_unresolved/i);
204
- await fs.rm(repoRoot, { recursive: true, force: true });
205
- });
206
- it('ignores legacy parity/coverage fields when exact_pairs are valid', async () => {
207
- const repoRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'rule-lab-analyze-exact-legacy-'));
208
- const runId = 'run-x';
209
- const sliceId = 'slice-a';
210
- const slicePath = path.join(repoRoot, '.gitnexus', 'rules', 'lab', 'runs', runId, 'slices', sliceId, 'slice.json');
211
- await writeJson(slicePath, {
212
- id: sliceId,
213
- trigger_family: 'event_delegate',
214
- resource_types: ['syncvar_hook'],
215
- host_base_type: ['network_behaviour'],
216
- required_hops: ['code_runtime'],
217
- exact_pairs: [
218
- {
219
- id: 'pair-a',
220
- binding_kind: 'method_triggers_method',
221
- source_anchor: { file: 'Assets/Gameplay/SourceA.cs', line: 12, symbol: 'SourceA.Trigger' },
222
- target_anchor: { file: 'Assets/Gameplay/TargetA.cs', line: 32, symbol: 'TargetA.OnTrigger' },
223
- },
224
- ],
225
- coverage_gate: {
226
- status: 'blocked',
227
- reason: 'coverage_incomplete',
228
- processed_user_matches: 0,
229
- user_raw_matches: 9,
230
- },
231
- parity_status: {
232
- status: 'blocked',
233
- reason: 'parity_missing_rules_slice',
234
- },
235
- });
236
- const analyzed = await analyzeRuleLabSlice({ repoPath: repoRoot, runId, sliceId });
237
- expect(analyzed.candidates).toHaveLength(1);
238
- expect(analyzed.candidates[0].exact_pair?.id).toBe('pair-a');
239
- await fs.rm(repoRoot, { recursive: true, force: true });
240
- });
241
- it('rejects placeholder run/slice ids', async () => {
242
- const repoRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'rule-lab-analyze-exact-placeholder-'));
243
- await expect(analyzeRuleLabSlice({ repoPath: repoRoot, runId: '<run_id>', sliceId: '<slice_id>' })).rejects.toThrow(/placeholder/i);
244
- await fs.rm(repoRoot, { recursive: true, force: true });
245
- });
246
- });
@@ -1,5 +0,0 @@
1
- import { type RuleBundleFamily } from './compiled-bundles.js';
2
- export declare function compileRules(options: {
3
- repoPath?: string;
4
- family?: RuleBundleFamily;
5
- }): Promise<void>;
@@ -1,51 +0,0 @@
1
- import fs from 'node:fs/promises';
2
- import path from 'node:path';
3
- import { parseRuleYaml } from '../mcp/local/runtime-claim-rule-registry.js';
4
- import { writeCompiledRuleBundle } from './compiled-bundles.js';
5
- export async function compileRules(options) {
6
- const repoPath = path.resolve(options.repoPath || process.cwd());
7
- const family = options.family || 'analyze_rules';
8
- const rulesRoot = path.join(repoPath, '.gitnexus', 'rules');
9
- const catalogPath = path.join(rulesRoot, 'catalog.json');
10
- let catalog;
11
- try {
12
- catalog = JSON.parse(await fs.readFile(catalogPath, 'utf-8'));
13
- }
14
- catch {
15
- console.error(`No catalog.json found at ${catalogPath}`);
16
- process.exitCode = 1;
17
- return;
18
- }
19
- const entries = catalog.rules.filter((e) => e.enabled !== false && e.family === family);
20
- if (entries.length === 0) {
21
- console.log(`No enabled ${family} rules in catalog.`);
22
- return;
23
- }
24
- const compiled = [];
25
- for (const entry of entries) {
26
- const yamlPath = path.join(rulesRoot, entry.file);
27
- const raw = await fs.readFile(yamlPath, 'utf-8');
28
- const rule = parseRuleYaml(raw, entry.file);
29
- compiled.push({
30
- id: rule.id,
31
- version: rule.version,
32
- trigger_family: rule.trigger_family,
33
- trigger_tokens: [...(rule.match?.trigger_tokens || [])],
34
- resource_types: [...rule.resource_types],
35
- host_base_type: [...rule.host_base_type],
36
- required_hops: [...rule.required_hops],
37
- guarantees: [...rule.guarantees],
38
- non_guarantees: [...rule.non_guarantees],
39
- next_action: rule.next_action || '',
40
- file_path: entry.file,
41
- match: rule.match || { trigger_tokens: [] },
42
- topology: [],
43
- closure: { required_hops: rule.required_hops, failure_map: {} },
44
- claims: { guarantees: rule.guarantees, non_guarantees: rule.non_guarantees, next_action: rule.next_action || '' },
45
- ...(rule.resource_bindings ? { resource_bindings: rule.resource_bindings } : {}),
46
- ...(rule.lifecycle_overrides ? { lifecycle_overrides: rule.lifecycle_overrides } : {}),
47
- });
48
- }
49
- const outPath = await writeCompiledRuleBundle(rulesRoot, family, compiled);
50
- console.log(`Compiled ${compiled.length} ${family} rules → ${outPath}`);
51
- }
@@ -1,30 +0,0 @@
1
- import type { RuleDslClaims, RuleDslClosure, RuleDslMatch, RuleDslTopologyHop } from './types.js';
2
- export type RuleBundleFamily = 'analyze_rules' | 'retrieval_rules' | 'verification_rules';
3
- export interface StageAwareCompiledRule {
4
- id: string;
5
- version: string;
6
- trigger_family: string;
7
- trigger_tokens: string[];
8
- resource_types: string[];
9
- host_base_type: string[];
10
- required_hops: string[];
11
- guarantees: string[];
12
- non_guarantees: string[];
13
- next_action: string;
14
- file_path: string;
15
- match: RuleDslMatch;
16
- topology: RuleDslTopologyHop[];
17
- closure: RuleDslClosure;
18
- claims: RuleDslClaims;
19
- resource_bindings?: import('./types.js').UnityResourceBinding[];
20
- lifecycle_overrides?: import('./types.js').LifecycleOverrides;
21
- }
22
- export interface CompiledRuleBundle {
23
- bundle_version: '2.0.0';
24
- family: RuleBundleFamily;
25
- generated_at: string;
26
- rules: StageAwareCompiledRule[];
27
- }
28
- export declare function compiledBundlePath(rulesRoot: string, family: RuleBundleFamily): string;
29
- export declare function writeCompiledRuleBundle(rulesRoot: string, family: RuleBundleFamily, rules: StageAwareCompiledRule[]): Promise<string>;
30
- export declare function loadCompiledRuleBundle(repoPath: string, family: RuleBundleFamily, rulesRoot?: string): Promise<CompiledRuleBundle | undefined>;
@@ -1,36 +0,0 @@
1
- import fs from 'node:fs/promises';
2
- import path from 'node:path';
3
- export function compiledBundlePath(rulesRoot, family) {
4
- return path.join(path.resolve(rulesRoot), 'compiled', `${family}.v2.json`);
5
- }
6
- export async function writeCompiledRuleBundle(rulesRoot, family, rules) {
7
- const outPath = compiledBundlePath(rulesRoot, family);
8
- const bundle = {
9
- bundle_version: '2.0.0',
10
- family,
11
- generated_at: new Date().toISOString(),
12
- rules,
13
- };
14
- await fs.mkdir(path.dirname(outPath), { recursive: true });
15
- await fs.writeFile(outPath, `${JSON.stringify(bundle, null, 2)}\n`, 'utf-8');
16
- return outPath;
17
- }
18
- export async function loadCompiledRuleBundle(repoPath, family, rulesRoot) {
19
- const root = rulesRoot
20
- ? path.resolve(rulesRoot)
21
- : path.join(path.resolve(repoPath), '.gitnexus', 'rules');
22
- const bundlePath = compiledBundlePath(root, family);
23
- try {
24
- const raw = await fs.readFile(bundlePath, 'utf-8');
25
- const parsed = JSON.parse(raw);
26
- if (parsed.family !== family || !Array.isArray(parsed.rules)) {
27
- throw new Error(`Invalid compiled ${family} bundle: ${bundlePath}`);
28
- }
29
- return parsed;
30
- }
31
- catch (error) {
32
- if (error?.code === 'ENOENT')
33
- return undefined;
34
- throw error;
35
- }
36
- }
@@ -1,33 +0,0 @@
1
- import { getRuleLabPaths } from './paths.js';
2
- import type { RuleDslMatch, RuleDslTopologyHop, RuleDslClosure, RuleDslClaims, UnityResourceBinding } from './types.js';
3
- export interface CurateInput {
4
- repoPath: string;
5
- runId: string;
6
- sliceId: string;
7
- inputPath: string;
8
- }
9
- export interface CuratedStep {
10
- hop_type?: string;
11
- anchor: string;
12
- snippet: string;
13
- }
14
- export interface CuratedItem {
15
- id: string;
16
- rule_id?: string;
17
- title?: string;
18
- match?: RuleDslMatch;
19
- topology?: RuleDslTopologyHop[];
20
- closure?: RuleDslClosure;
21
- claims?: RuleDslClaims;
22
- resource_bindings?: UnityResourceBinding[];
23
- confirmed_chain: {
24
- steps: CuratedStep[];
25
- };
26
- guarantees: string[];
27
- non_guarantees: string[];
28
- }
29
- export interface CurateOutput {
30
- paths: ReturnType<typeof getRuleLabPaths>;
31
- curated: CuratedItem[];
32
- }
33
- export declare function curateRuleLabSlice(input: CurateInput): Promise<CurateOutput>;
@@ -1,155 +0,0 @@
1
- import fs from 'node:fs/promises';
2
- import path from 'node:path';
3
- import { getRuleLabPaths } from './paths.js';
4
- const PLACEHOLDER_RE = /TODO|TBD|placeholder|<[^>]+>/i;
5
- function hasPlaceholderText(value) {
6
- return PLACEHOLDER_RE.test(String(value || ''));
7
- }
8
- function normalizeForSet(values) {
9
- return new Set(values.map((value) => value.trim().toLowerCase()));
10
- }
11
- function ensureStringArray(values, field) {
12
- if (!Array.isArray(values) || values.length === 0) {
13
- throw new Error(`${field} must be non-empty`);
14
- }
15
- if (values.some((value) => !String(value || '').trim())) {
16
- throw new Error(`${field} entries must be non-empty strings`);
17
- }
18
- return values.map((value) => String(value).trim());
19
- }
20
- function validateDslFields(item) {
21
- if (!item.match || !Array.isArray(item.match.trigger_tokens) || item.match.trigger_tokens.length === 0) {
22
- throw new Error('match.trigger_tokens must be non-empty');
23
- }
24
- ensureStringArray(item.match.trigger_tokens, 'match.trigger_tokens');
25
- if (!Array.isArray(item.topology) || item.topology.length === 0) {
26
- throw new Error('topology must be non-empty');
27
- }
28
- item.topology.forEach((hop, index) => {
29
- if (!String(hop.hop || '').trim()) {
30
- throw new Error(`topology[${index}].hop must be non-empty`);
31
- }
32
- if (!String(hop.edge?.kind || '').trim()) {
33
- throw new Error(`topology[${index}].edge.kind must be non-empty`);
34
- }
35
- });
36
- if (!item.closure || !Array.isArray(item.closure.required_hops) || item.closure.required_hops.length === 0) {
37
- throw new Error('closure.required_hops must be non-empty');
38
- }
39
- if (!item.closure.failure_map || Object.keys(item.closure.failure_map).length === 0) {
40
- throw new Error('closure.failure_map must be non-empty');
41
- }
42
- ensureStringArray(item.closure.required_hops, 'closure.required_hops');
43
- if (!item.claims) {
44
- throw new Error('claims must be present');
45
- }
46
- ensureStringArray(item.claims.guarantees, 'claims.guarantees');
47
- ensureStringArray(item.claims.non_guarantees, 'claims.non_guarantees');
48
- if (!String(item.claims.next_action || '').trim()) {
49
- throw new Error('claims.next_action must be non-empty');
50
- }
51
- }
52
- function validateCuratedItem(item) {
53
- if (!Array.isArray(item.confirmed_chain?.steps) || item.confirmed_chain.steps.length === 0) {
54
- throw new Error('confirmed_chain.steps must be non-empty for promotion');
55
- }
56
- item.confirmed_chain.steps.forEach((step, index) => {
57
- if (!String(step.anchor || '').trim()) {
58
- throw new Error(`confirmed_chain.steps[${index}].anchor must be non-empty`);
59
- }
60
- if (!String(step.snippet || '').trim()) {
61
- throw new Error(`confirmed_chain.steps[${index}].snippet must be non-empty`);
62
- }
63
- if (hasPlaceholderText(step.anchor) || hasPlaceholderText(step.snippet)) {
64
- throw new Error(`confirmed_chain.steps[${index}] contains placeholder text`);
65
- }
66
- });
67
- if (!Array.isArray(item.guarantees) || item.guarantees.length === 0) {
68
- throw new Error('guarantees must be non-empty');
69
- }
70
- if (!Array.isArray(item.non_guarantees) || item.non_guarantees.length === 0) {
71
- throw new Error('non_guarantees must be non-empty');
72
- }
73
- if (item.guarantees.some((entry) => !String(entry || '').trim()) || item.non_guarantees.some((entry) => !String(entry || '').trim())) {
74
- throw new Error('guarantees/non_guarantees entries must be non-empty strings');
75
- }
76
- if (hasPlaceholderText(JSON.stringify(item))) {
77
- throw new Error('curated item contains placeholder text');
78
- }
79
- if (Array.isArray(item.resource_bindings)) {
80
- const rawBindings = JSON.stringify(item.resource_bindings);
81
- if (/UnknownClass|UnknownMethod|UnknownSource|UnknownTarget/i.test(rawBindings)) {
82
- throw new Error('binding unresolved: unknown placeholder binding values are forbidden');
83
- }
84
- }
85
- const guaranteeSet = normalizeForSet(item.guarantees);
86
- const nonGuaranteeSet = normalizeForSet(item.non_guarantees);
87
- const overlap = [...guaranteeSet].filter((entry) => nonGuaranteeSet.has(entry));
88
- if (overlap.length === guaranteeSet.size && overlap.length === nonGuaranteeSet.size) {
89
- throw new Error('guarantees and non_guarantees must have semantic distinction');
90
- }
91
- validateDslFields(item);
92
- }
93
- function toDslDraft(item) {
94
- return {
95
- id: String(item.rule_id || item.id || '').trim(),
96
- version: '2.0.0',
97
- match: item.match,
98
- topology: item.topology,
99
- closure: item.closure,
100
- claims: item.claims,
101
- ...(Array.isArray(item.resource_bindings) && item.resource_bindings.length > 0
102
- ? { resource_bindings: item.resource_bindings }
103
- : {}),
104
- };
105
- }
106
- function validateDslDraft(draft) {
107
- if (!String(draft.id || '').trim()) {
108
- throw new Error('dsl draft id must be non-empty');
109
- }
110
- ensureStringArray(draft.match.trigger_tokens, 'match.trigger_tokens');
111
- if (!Array.isArray(draft.topology) || draft.topology.length === 0) {
112
- throw new Error('topology must be non-empty');
113
- }
114
- ensureStringArray(draft.closure.required_hops, 'closure.required_hops');
115
- if (!draft.closure.failure_map || Object.keys(draft.closure.failure_map).length === 0) {
116
- throw new Error('closure.failure_map must be non-empty');
117
- }
118
- ensureStringArray(draft.claims.guarantees, 'claims.guarantees');
119
- ensureStringArray(draft.claims.non_guarantees, 'claims.non_guarantees');
120
- if (!String(draft.claims.next_action || '').trim()) {
121
- throw new Error('claims.next_action must be non-empty');
122
- }
123
- }
124
- export async function curateRuleLabSlice(input) {
125
- const normalizedRepoPath = path.resolve(input.repoPath);
126
- const paths = getRuleLabPaths(normalizedRepoPath, input.runId, input.sliceId);
127
- const raw = await fs.readFile(path.resolve(input.inputPath), 'utf-8');
128
- const parsed = JSON.parse(raw);
129
- const curated = Array.isArray(parsed.curated) ? parsed.curated : [];
130
- if (curated.length === 0) {
131
- throw new Error('curated must contain at least one candidate');
132
- }
133
- curated.forEach(validateCuratedItem);
134
- const drafts = curated.map((item) => toDslDraft(item));
135
- drafts.forEach(validateDslDraft);
136
- const firstDraft = drafts[0];
137
- const sliceDir = path.dirname(paths.curatedPath);
138
- await fs.mkdir(path.dirname(paths.curatedPath), { recursive: true });
139
- await fs.writeFile(paths.curatedPath, `${JSON.stringify({ run_id: input.runId, slice_id: input.sliceId, curated }, null, 2)}\n`, 'utf-8');
140
- await fs.writeFile(path.join(sliceDir, 'dsl-drafts.json'), `${JSON.stringify({ run_id: input.runId, slice_id: input.sliceId, drafts }, null, 2)}\n`, 'utf-8');
141
- if (drafts.length === 1) {
142
- await fs.writeFile(path.join(sliceDir, 'dsl-draft.json'), `${JSON.stringify(firstDraft, null, 2)}\n`, 'utf-8');
143
- }
144
- else {
145
- await fs.writeFile(path.join(sliceDir, 'dsl-draft.json'), `${JSON.stringify({
146
- compatibility_warning: 'multi-draft mode active; use dsl-drafts.json for complete draft set',
147
- primary_draft_id: firstDraft.id,
148
- primary_draft: firstDraft,
149
- }, null, 2)}\n`, 'utf-8');
150
- }
151
- return {
152
- paths,
153
- curated,
154
- };
155
- }
@@ -1 +0,0 @@
1
- export {};