@buba_71/levit 0.4.0 → 0.8.2

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 (74) hide show
  1. package/README.md +182 -10
  2. package/dist/bin/cli.js +58 -48
  3. package/dist/src/commands/decision.js +34 -19
  4. package/dist/src/commands/feature.js +117 -19
  5. package/dist/src/commands/handoff.js +34 -12
  6. package/dist/src/commands/index.js +3 -1
  7. package/dist/src/commands/init.js +53 -39
  8. package/dist/src/commands/validate.js +84 -0
  9. package/dist/src/core/error_helper.js +93 -0
  10. package/dist/src/core/errors.js +25 -0
  11. package/dist/src/core/frontmatter.js +62 -0
  12. package/dist/src/core/logger.js +77 -0
  13. package/dist/src/core/table.js +63 -0
  14. package/dist/src/init.js +9 -0
  15. package/dist/src/readers/decision_reader.js +47 -0
  16. package/dist/src/readers/feature_reader.js +48 -0
  17. package/dist/src/readers/handoff_reader.js +47 -0
  18. package/dist/src/services/decision_service.js +49 -0
  19. package/dist/src/services/feature_service.js +89 -0
  20. package/dist/src/services/handoff_service.js +37 -0
  21. package/dist/src/services/manifest_service.js +89 -0
  22. package/dist/src/services/project_service.js +39 -0
  23. package/dist/src/services/validation_service.js +461 -0
  24. package/dist/src/types/domain.js +2 -0
  25. package/dist/src/types/index.js +2 -0
  26. package/dist/src/types/manifest.js +26 -0
  27. package/dist/tests/{init.test.js → cli/integration.test.js} +79 -39
  28. package/dist/tests/services/decision_service.test.js +27 -0
  29. package/dist/tests/services/feature_service.test.js +42 -0
  30. package/dist/tests/services/handoff_service.test.js +28 -0
  31. package/dist/tests/services/manifest_service.test.js +189 -0
  32. package/dist/tests/services/validation_service.test.js +196 -0
  33. package/package.json +7 -2
  34. package/templates/default/.github/workflows/README.md +56 -0
  35. package/templates/default/.github/workflows/levit-validate.yml +93 -0
  36. package/templates/default/.gitlab-ci.yml +73 -0
  37. package/templates/default/.levit/AGENT_CONTRACT.md +34 -0
  38. package/templates/default/.levit/AGENT_ONBOARDING.md +5 -4
  39. package/templates/default/.levit/decisions/.gitkeep +0 -0
  40. package/templates/default/{features → .levit/features}/INTENT.md +9 -0
  41. package/templates/default/{features → .levit/features}/README.md +2 -2
  42. package/templates/default/.levit/handoff/.gitkeep +0 -0
  43. package/templates/default/HUMAN_AGENT_MANAGER.md +654 -0
  44. package/templates/default/MIGRATION_GUIDE.md +597 -0
  45. package/templates/default/README.md +26 -7
  46. package/templates/symfony/.github/workflows/README.md +56 -0
  47. package/templates/symfony/.github/workflows/levit-validate.yml +82 -0
  48. package/templates/symfony/.gitlab-ci.yml +62 -0
  49. package/templates/symfony/.levit/AGENT_CONTRACT.md +34 -0
  50. package/templates/symfony/.levit/AGENT_ONBOARDING.md +124 -0
  51. package/templates/symfony/.levit/decisions/.gitkeep +0 -0
  52. package/templates/symfony/.levit/features/INTENT.md +32 -0
  53. package/templates/symfony/.levit/features/README.md +11 -0
  54. package/templates/symfony/.levit/handoff/.gitkeep +0 -0
  55. package/templates/symfony/.levit/prompts/global-rules.md +10 -0
  56. package/templates/symfony/.levit/prompts/refactoring-guidelines.md +9 -0
  57. package/templates/symfony/.levit/workflows/example-task.md +9 -0
  58. package/templates/symfony/.levit/workflows/submit-for-review.md +18 -0
  59. package/templates/symfony/HUMAN_AGENT_MANAGER.md +654 -0
  60. package/templates/symfony/MIGRATION_GUIDE.md +597 -0
  61. package/templates/symfony/README.md +101 -0
  62. package/templates/symfony/SOCIAL_CONTRACT.md +34 -0
  63. package/templates/default/.levit/decision-record.md +0 -19
  64. package/templates/default/package.json +0 -11
  65. /package/templates/default/{agents → .levit/agents}/AGENTS.md +0 -0
  66. /package/templates/default/{agents → .levit/agents}/boundaries.md +0 -0
  67. /package/templates/default/{docs → .levit/docs}/architecture.md +0 -0
  68. /package/templates/default/{evals → .levit/evals}/README.md +0 -0
  69. /package/templates/default/{evals → .levit/evals}/conformance.eval.ts +0 -0
  70. /package/templates/default/{pipelines → .levit/pipelines}/README.md +0 -0
  71. /package/templates/default/{roles → .levit/roles}/README.md +0 -0
  72. /package/templates/default/{roles → .levit/roles}/devops.md +0 -0
  73. /package/templates/default/{roles → .levit/roles}/qa.md +0 -0
  74. /package/templates/default/{roles → .levit/roles}/security.md +0 -0
@@ -0,0 +1,196 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const node_test_1 = __importDefault(require("node:test"));
7
+ const node_assert_1 = __importDefault(require("node:assert"));
8
+ const fs_extra_1 = __importDefault(require("fs-extra"));
9
+ const node_path_1 = __importDefault(require("node:path"));
10
+ const node_os_1 = __importDefault(require("node:os"));
11
+ const validation_service_1 = require("../../src/services/validation_service");
12
+ (0, node_test_1.default)("ValidationService reports errors if core directories are missing", () => {
13
+ const tempDir = fs_extra_1.default.mkdtempSync(node_path_1.default.join(node_os_1.default.tmpdir(), "validation-service-test-"));
14
+ // Validate empty dir
15
+ const result = validation_service_1.ValidationService.validate(tempDir);
16
+ // Expect invalid
17
+ node_assert_1.default.strictEqual(result.valid, false);
18
+ node_assert_1.default.ok(result.metrics.errors > 0, "Should have errors");
19
+ // Check specific error code presence
20
+ const missingDirs = result.issues.filter(i => i.code === "MISSING_DIRECTORY");
21
+ node_assert_1.default.ok(missingDirs.length > 0, "Should report missing directories");
22
+ fs_extra_1.default.rmSync(tempDir, { recursive: true, force: true });
23
+ });
24
+ (0, node_test_1.default)("ValidationService passes for valid structure", () => {
25
+ const tempDir = fs_extra_1.default.mkdtempSync(node_path_1.default.join(node_os_1.default.tmpdir(), "validation-service-succ-"));
26
+ // Scout scaffolding: .levit/features, .levit/decisions, .levit/handoff, core files
27
+ const dirs = [".levit/features", ".levit/decisions", ".levit/handoff"];
28
+ dirs.forEach(d => fs_extra_1.default.ensureDirSync(node_path_1.default.join(tempDir, d)));
29
+ const files = ["SOCIAL_CONTRACT.md", ".levit/AGENT_CONTRACT.md", ".levit/AGENT_ONBOARDING.md"];
30
+ files.forEach(f => fs_extra_1.default.writeFileSync(node_path_1.default.join(tempDir, f), "content"));
31
+ const result = validation_service_1.ValidationService.validate(tempDir);
32
+ node_assert_1.default.strictEqual(result.valid, true);
33
+ fs_extra_1.default.rmSync(tempDir, { recursive: true, force: true });
34
+ });
35
+ (0, node_test_1.default)("ValidationService detects feature with invalid frontmatter", () => {
36
+ const tempDir = fs_extra_1.default.mkdtempSync(node_path_1.default.join(node_os_1.default.tmpdir(), "validation-service-test-"));
37
+ const featuresDir = node_path_1.default.join(tempDir, ".levit", "features");
38
+ fs_extra_1.default.ensureDirSync(featuresDir);
39
+ // Create core structure
40
+ fs_extra_1.default.ensureDirSync(node_path_1.default.join(tempDir, ".levit/decisions"));
41
+ fs_extra_1.default.ensureDirSync(node_path_1.default.join(tempDir, ".levit/handoff"));
42
+ fs_extra_1.default.writeFileSync(node_path_1.default.join(tempDir, "SOCIAL_CONTRACT.md"), "content");
43
+ fs_extra_1.default.writeFileSync(node_path_1.default.join(tempDir, ".levit/AGENT_CONTRACT.md"), "content");
44
+ fs_extra_1.default.writeFileSync(node_path_1.default.join(tempDir, ".levit/AGENT_ONBOARDING.md"), "content");
45
+ // Create feature with missing required fields
46
+ const invalidFeature = `---
47
+ id: 001
48
+ status: active
49
+ # Missing: owner, last_updated, risk_level, depends_on
50
+
51
+ # INTENT: Test Feature
52
+ `;
53
+ fs_extra_1.default.writeFileSync(node_path_1.default.join(featuresDir, "001-test.md"), invalidFeature);
54
+ const result = validation_service_1.ValidationService.validate(tempDir);
55
+ node_assert_1.default.strictEqual(result.valid, false);
56
+ const frontmatterErrors = result.issues.filter(i => i.code === "INVALID_FRONTMATTER");
57
+ node_assert_1.default.ok(frontmatterErrors.length > 0, "Should report invalid frontmatter");
58
+ fs_extra_1.default.rmSync(tempDir, { recursive: true, force: true });
59
+ });
60
+ (0, node_test_1.default)("ValidationService detects feature without INTENT header", () => {
61
+ const tempDir = fs_extra_1.default.mkdtempSync(node_path_1.default.join(node_os_1.default.tmpdir(), "validation-service-test-"));
62
+ const featuresDir = node_path_1.default.join(tempDir, ".levit", "features");
63
+ fs_extra_1.default.ensureDirSync(featuresDir);
64
+ // Create core structure
65
+ fs_extra_1.default.ensureDirSync(node_path_1.default.join(tempDir, ".levit/decisions"));
66
+ fs_extra_1.default.ensureDirSync(node_path_1.default.join(tempDir, ".levit/handoff"));
67
+ fs_extra_1.default.writeFileSync(node_path_1.default.join(tempDir, "SOCIAL_CONTRACT.md"), "content");
68
+ fs_extra_1.default.writeFileSync(node_path_1.default.join(tempDir, ".levit/AGENT_CONTRACT.md"), "content");
69
+ fs_extra_1.default.writeFileSync(node_path_1.default.join(tempDir, ".levit/AGENT_ONBOARDING.md"), "content");
70
+ // Create feature without INTENT header
71
+ const featureWithoutIntent = `---
72
+ id: 001
73
+ status: active
74
+ owner: human
75
+ last_updated: 2026-01-01
76
+ risk_level: low
77
+ depends_on: []
78
+ ---
79
+
80
+ # Some other header
81
+ `;
82
+ fs_extra_1.default.writeFileSync(node_path_1.default.join(featuresDir, "001-test.md"), featureWithoutIntent);
83
+ const result = validation_service_1.ValidationService.validate(tempDir);
84
+ node_assert_1.default.strictEqual(result.valid, false);
85
+ const structureErrors = result.issues.filter(i => i.code === "INVALID_STRUCTURE");
86
+ node_assert_1.default.ok(structureErrors.length > 0, "Should report missing INTENT header");
87
+ fs_extra_1.default.rmSync(tempDir, { recursive: true, force: true });
88
+ });
89
+ (0, node_test_1.default)("ValidationService detects decision with invalid frontmatter", () => {
90
+ const tempDir = fs_extra_1.default.mkdtempSync(node_path_1.default.join(node_os_1.default.tmpdir(), "validation-service-test-"));
91
+ const decisionsDir = node_path_1.default.join(tempDir, ".levit/decisions");
92
+ fs_extra_1.default.ensureDirSync(decisionsDir);
93
+ // Create core structure
94
+ fs_extra_1.default.ensureDirSync(node_path_1.default.join(tempDir, ".levit", "features"));
95
+ fs_extra_1.default.ensureDirSync(node_path_1.default.join(tempDir, ".levit", "handoff"));
96
+ fs_extra_1.default.writeFileSync(node_path_1.default.join(tempDir, "SOCIAL_CONTRACT.md"), "content");
97
+ fs_extra_1.default.writeFileSync(node_path_1.default.join(tempDir, ".levit/AGENT_CONTRACT.md"), "content");
98
+ fs_extra_1.default.writeFileSync(node_path_1.default.join(tempDir, ".levit/AGENT_ONBOARDING.md"), "content");
99
+ // Create decision with invalid YAML
100
+ const invalidDecision = `---
101
+ id: ADR-001
102
+ status: draft
103
+ owner: human
104
+ last_updated: 2026-01-01
105
+ risk_level: low
106
+ depends_on: [invalid: yaml: syntax]
107
+ ---
108
+
109
+ # ADR 001: Test
110
+ `;
111
+ fs_extra_1.default.writeFileSync(node_path_1.default.join(decisionsDir, "ADR-001-test.md"), invalidDecision);
112
+ const result = validation_service_1.ValidationService.validate(tempDir);
113
+ node_assert_1.default.strictEqual(result.valid, false);
114
+ const frontmatterErrors = result.issues.filter(i => i.code === "INVALID_FRONTMATTER");
115
+ node_assert_1.default.ok(frontmatterErrors.length > 0, "Should report invalid YAML");
116
+ fs_extra_1.default.rmSync(tempDir, { recursive: true, force: true });
117
+ });
118
+ (0, node_test_1.default)("ValidationService detects handoff with missing frontmatter", () => {
119
+ const tempDir = fs_extra_1.default.mkdtempSync(node_path_1.default.join(node_os_1.default.tmpdir(), "validation-service-test-"));
120
+ const handoffDir = node_path_1.default.join(tempDir, ".levit/handoff");
121
+ fs_extra_1.default.ensureDirSync(handoffDir);
122
+ // Create core structure
123
+ fs_extra_1.default.ensureDirSync(node_path_1.default.join(tempDir, ".levit", "features"));
124
+ fs_extra_1.default.ensureDirSync(node_path_1.default.join(tempDir, ".levit", "decisions"));
125
+ fs_extra_1.default.writeFileSync(node_path_1.default.join(tempDir, "SOCIAL_CONTRACT.md"), "content");
126
+ fs_extra_1.default.writeFileSync(node_path_1.default.join(tempDir, ".levit/AGENT_CONTRACT.md"), "content");
127
+ fs_extra_1.default.writeFileSync(node_path_1.default.join(tempDir, ".levit/AGENT_ONBOARDING.md"), "content");
128
+ // Create handoff without frontmatter
129
+ const handoffWithoutFrontmatter = `# Agent Handoff
130
+ No frontmatter here
131
+ `;
132
+ fs_extra_1.default.writeFileSync(node_path_1.default.join(handoffDir, "2026-01-01-test.md"), handoffWithoutFrontmatter);
133
+ const result = validation_service_1.ValidationService.validate(tempDir);
134
+ node_assert_1.default.strictEqual(result.valid, false);
135
+ const frontmatterErrors = result.issues.filter(i => i.code === "INVALID_FRONTMATTER");
136
+ node_assert_1.default.ok(frontmatterErrors.length > 0, "Should report missing frontmatter");
137
+ fs_extra_1.default.rmSync(tempDir, { recursive: true, force: true });
138
+ });
139
+ (0, node_test_1.default)("ValidationService reports warning when no features exist", () => {
140
+ const tempDir = fs_extra_1.default.mkdtempSync(node_path_1.default.join(node_os_1.default.tmpdir(), "validation-service-test-"));
141
+ const featuresDir = node_path_1.default.join(tempDir, ".levit", "features");
142
+ fs_extra_1.default.ensureDirSync(featuresDir);
143
+ // Create core structure
144
+ fs_extra_1.default.ensureDirSync(node_path_1.default.join(tempDir, ".levit/decisions"));
145
+ fs_extra_1.default.ensureDirSync(node_path_1.default.join(tempDir, ".levit/handoff"));
146
+ fs_extra_1.default.writeFileSync(node_path_1.default.join(tempDir, "SOCIAL_CONTRACT.md"), "content");
147
+ fs_extra_1.default.writeFileSync(node_path_1.default.join(tempDir, ".levit/AGENT_CONTRACT.md"), "content");
148
+ fs_extra_1.default.writeFileSync(node_path_1.default.join(tempDir, ".levit/AGENT_ONBOARDING.md"), "content");
149
+ // No features in features directory
150
+ const result = validation_service_1.ValidationService.validate(tempDir);
151
+ node_assert_1.default.strictEqual(result.valid, true, "Should be valid (only warning)");
152
+ node_assert_1.default.ok(result.metrics.warnings > 0, "Should have warnings");
153
+ const noFeaturesWarning = result.issues.find(i => i.code === "NO_FEATURES");
154
+ node_assert_1.default.ok(noFeaturesWarning, "Should report no features warning");
155
+ fs_extra_1.default.rmSync(tempDir, { recursive: true, force: true });
156
+ });
157
+ (0, node_test_1.default)("ValidationService counts files scanned correctly", () => {
158
+ const tempDir = fs_extra_1.default.mkdtempSync(node_path_1.default.join(node_os_1.default.tmpdir(), "validation-service-test-"));
159
+ const featuresDir = node_path_1.default.join(tempDir, ".levit", "features");
160
+ fs_extra_1.default.ensureDirSync(featuresDir);
161
+ // Create core structure
162
+ fs_extra_1.default.ensureDirSync(node_path_1.default.join(tempDir, ".levit/decisions"));
163
+ fs_extra_1.default.ensureDirSync(node_path_1.default.join(tempDir, ".levit/handoff"));
164
+ fs_extra_1.default.writeFileSync(node_path_1.default.join(tempDir, "SOCIAL_CONTRACT.md"), "content");
165
+ fs_extra_1.default.writeFileSync(node_path_1.default.join(tempDir, ".levit/AGENT_CONTRACT.md"), "content");
166
+ fs_extra_1.default.writeFileSync(node_path_1.default.join(tempDir, ".levit/AGENT_ONBOARDING.md"), "content");
167
+ // Create valid feature
168
+ const validFeature = `---
169
+ id: 001
170
+ status: active
171
+ owner: human
172
+ last_updated: 2026-01-01
173
+ risk_level: low
174
+ depends_on: []
175
+ ---
176
+
177
+ # INTENT: Test Feature
178
+ `;
179
+ fs_extra_1.default.writeFileSync(node_path_1.default.join(featuresDir, "001-test.md"), validFeature);
180
+ // Create valid decision
181
+ const validDecision = `---
182
+ id: ADR-001
183
+ status: draft
184
+ owner: human
185
+ last_updated: 2026-01-01
186
+ risk_level: low
187
+ depends_on: []
188
+ ---
189
+
190
+ # ADR 001: Test Decision
191
+ `;
192
+ fs_extra_1.default.writeFileSync(node_path_1.default.join(tempDir, ".levit/decisions", "ADR-001-test.md"), validDecision);
193
+ const result = validation_service_1.ValidationService.validate(tempDir);
194
+ node_assert_1.default.strictEqual(result.metrics.filesScanned, 2, "Should scan 2 files (1 feature + 1 decision)");
195
+ fs_extra_1.default.rmSync(tempDir, { recursive: true, force: true });
196
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@buba_71/levit",
3
- "version": "0.4.0",
3
+ "version": "0.8.2",
4
4
  "description": "Hybrid starter kit for Antigravity projects",
5
5
  "author": "David BUBA",
6
6
  "license": "MIT",
@@ -19,14 +19,19 @@
19
19
  "main": "dist/src/init.js",
20
20
  "scripts": {
21
21
  "build": "tsc && chmod +x dist/bin/cli.js",
22
+ "prepublishOnly": "npm run build",
22
23
  "start": "node dist/bin/cli.js",
23
24
  "test": "npm run build && node --test dist/tests"
24
25
  },
25
26
  "dependencies": {
26
- "fs-extra": "^11.2.0"
27
+ "fs-extra": "^11.2.0",
28
+ "js-yaml": "^4.1.1",
29
+ "chalk": "^4.1.2",
30
+ "cli-table3": "^0.6.5"
27
31
  },
28
32
  "devDependencies": {
29
33
  "@types/fs-extra": "^11.0.4",
34
+ "@types/js-yaml": "^4.0.9",
30
35
  "@types/node": "^20.11.0",
31
36
  "typescript": "^5.3.0"
32
37
  }
@@ -0,0 +1,56 @@
1
+ # GitHub Actions Workflows
2
+
3
+ This directory contains CI/CD workflows for levit-kit projects.
4
+
5
+ ## Available Workflows
6
+
7
+ ### `levit-validate.yml`
8
+
9
+ Validates the levit-kit project structure on every push and pull request.
10
+
11
+ **What it does**:
12
+ - Runs `levit validate` to check project structure
13
+ - Fails the build if validation errors are found
14
+ - Uploads validation results as artifacts
15
+ - Displays results in GitHub Actions summary
16
+
17
+ **When it runs**:
18
+ - On pushes to `main`, `master`, or `develop` branches
19
+ - On pull requests targeting these branches
20
+
21
+ **How to use**:
22
+ 1. This workflow is automatically included in levit-kit projects
23
+ 2. No configuration needed - it works out of the box
24
+ 3. Customize the `on:` section if you use different branch names
25
+
26
+ **Customization**:
27
+ Edit `.github/workflows/levit-validate.yml` to:
28
+ - Change branch names
29
+ - Add additional validation steps
30
+ - Integrate with other workflows
31
+ - Add notifications
32
+
33
+ ## Adding Custom Workflows
34
+
35
+ You can add additional workflows for:
36
+ - Feature status checks
37
+ - Decision record validation
38
+ - Handoff completeness checks
39
+ - Custom evals
40
+
41
+ Example structure:
42
+ ```yaml
43
+ name: Custom Validation
44
+ on: [push, pull_request]
45
+ jobs:
46
+ custom-check:
47
+ runs-on: ubuntu-latest
48
+ steps:
49
+ - uses: actions/checkout@v4
50
+ - run: your-custom-script.sh
51
+ ```
52
+
53
+ ---
54
+
55
+ *For more information, see the [levit-kit documentation](https://github.com/buba71/levit-kit).*
56
+
@@ -0,0 +1,93 @@
1
+ name: Validate Levit Project
2
+
3
+ on:
4
+ push:
5
+ branches: [ main, master, develop ]
6
+ pull_request:
7
+ branches: [ main, master, develop ]
8
+
9
+ jobs:
10
+ validate:
11
+ name: Validate levit-kit Structure
12
+ runs-on: ubuntu-latest
13
+
14
+ steps:
15
+ - name: Checkout code
16
+ uses: actions/checkout@v4
17
+
18
+ - name: Setup Node.js
19
+ uses: actions/setup-node@v4
20
+ with:
21
+ node-version: '20'
22
+ cache: 'npm'
23
+
24
+ - name: Validate levit-kit structure
25
+ id: validate
26
+ run: |
27
+ npx @buba_71/levit validate --json > validation.json 2>&1 || VALIDATION_EXIT=$?
28
+ if [ -n "$VALIDATION_EXIT" ]; then
29
+ echo "validation_failed=true" >> $GITHUB_OUTPUT
30
+ else
31
+ echo "validation_failed=false" >> $GITHUB_OUTPUT
32
+ fi
33
+
34
+ - name: Display validation results
35
+ if: always()
36
+ run: |
37
+ if [ -f validation.json ]; then
38
+ echo "## Validation Results" >> $GITHUB_STEP_SUMMARY
39
+ echo '```json' >> $GITHUB_STEP_SUMMARY
40
+ cat validation.json >> $GITHUB_STEP_SUMMARY
41
+ echo '```' >> $GITHUB_STEP_SUMMARY
42
+
43
+ # Check for errors in JSON output
44
+ ERRORS=$(node -e "
45
+ try {
46
+ const fs = require('fs');
47
+ const content = fs.readFileSync('validation.json', 'utf8');
48
+ const lines = content.split('\\n').filter(l => l.trim());
49
+ let errorCount = 0;
50
+ for (const line of lines) {
51
+ try {
52
+ const obj = JSON.parse(line);
53
+ // Check for ERROR level or validation failure messages
54
+ if (obj.level === 'ERROR' ||
55
+ (obj.message && (
56
+ obj.message.toLowerCase().includes('error') ||
57
+ obj.message.toLowerCase().includes('validation failed') ||
58
+ obj.message.toLowerCase().includes('failed')
59
+ ))) {
60
+ errorCount++;
61
+ }
62
+ } catch (e) {
63
+ // Non-JSON lines might be error messages
64
+ if (line.toLowerCase().includes('error') || line.toLowerCase().includes('failed')) {
65
+ errorCount++;
66
+ }
67
+ }
68
+ }
69
+ console.log(errorCount);
70
+ } catch (e) {
71
+ console.log('0');
72
+ }
73
+ " || echo "0")
74
+
75
+ if [ "$ERRORS" -gt 0 ] || [ "${{ steps.validate.outputs.validation_failed }}" == "true" ]; then
76
+ echo "❌ Validation failed"
77
+ exit 1
78
+ else
79
+ echo "✅ Validation passed"
80
+ fi
81
+ else
82
+ echo "⚠️ No validation output found"
83
+ exit 1
84
+ fi
85
+
86
+ - name: Upload validation results
87
+ if: always()
88
+ uses: actions/upload-artifact@v3
89
+ with:
90
+ name: validation-results
91
+ path: validation.json
92
+ if-no-files-found: ignore
93
+
@@ -0,0 +1,73 @@
1
+ # GitLab CI configuration for levit-kit validation
2
+ # Add this to your existing .gitlab-ci.yml or use it as a separate file
3
+
4
+ stages:
5
+ - validate
6
+
7
+ levit-validate:
8
+ stage: validate
9
+ image: node:20
10
+ before_script:
11
+ - npm install -g @buba_71/levit
12
+ script:
13
+ - |
14
+ echo "🔍 Validating levit-kit project structure..."
15
+ levit validate --json > validation.json 2>&1 || VALIDATION_EXIT=$?
16
+
17
+ if [ -f validation.json ]; then
18
+ echo "Validation results:"
19
+ cat validation.json
20
+
21
+ # Count errors in JSON output
22
+ ERRORS=$(node -e "
23
+ try {
24
+ const fs = require('fs');
25
+ const content = fs.readFileSync('validation.json', 'utf8');
26
+ const lines = content.split('\\n').filter(l => l.trim());
27
+ let errorCount = 0;
28
+ for (const line of lines) {
29
+ try {
30
+ const obj = JSON.parse(line);
31
+ // Check for ERROR level or validation failure messages
32
+ if (obj.level === 'ERROR' ||
33
+ (obj.message && (
34
+ obj.message.toLowerCase().includes('error') ||
35
+ obj.message.toLowerCase().includes('validation failed') ||
36
+ obj.message.toLowerCase().includes('failed')
37
+ ))) {
38
+ errorCount++;
39
+ }
40
+ } catch (e) {
41
+ // Non-JSON lines might be error messages
42
+ if (line.toLowerCase().includes('error') || line.toLowerCase().includes('failed')) {
43
+ errorCount++;
44
+ }
45
+ }
46
+ }
47
+ console.log(errorCount);
48
+ } catch (e) {
49
+ console.log('0');
50
+ }
51
+ " || echo "0")
52
+
53
+ if [ "$ERRORS" -gt 0 ] || [ -n "$VALIDATION_EXIT" ]; then
54
+ echo "❌ Validation failed with errors"
55
+ exit 1
56
+ else
57
+ echo "✅ Validation passed"
58
+ fi
59
+ else
60
+ echo "⚠️ No validation output found"
61
+ exit 1
62
+ fi
63
+ artifacts:
64
+ when: always
65
+ paths:
66
+ - validation.json
67
+ expire_in: 1 week
68
+ only:
69
+ - merge_requests
70
+ - main
71
+ - master
72
+ - develop
73
+
@@ -0,0 +1,34 @@
1
+ # AGENT_CONTRACT.md
2
+
3
+ > [!IMPORTANT]
4
+ > This document defines the social and technical contract between the **Human Operator** and any **AI Agent** working on this project.
5
+
6
+ ## 1. Social Contract & Philosophy
7
+ Our collaboration is based on the [SOCIAL_CONTRACT.md](file:///path/to/SOCIAL_CONTRACT.md) guidelines:
8
+ - **Human in the Loop**: AI proposes, Human disposes.
9
+ - **Cognitive Scaffolding**: Documentation is not a chore; it is the project's memory.
10
+
11
+ ## 2. Agent Mandates (MUST)
12
+ - **Traceability**: Every code change MUST be mapped to an intention in `features/`.
13
+ - **Decision Records**: Significant technical choices MUST be documented in `.levit/decisions/`.
14
+ - **Handoffs**: Leave a clear handoff in `.levit/handoff/` when ending a session.
15
+ - **Linter First**: Run `levit validate` before declaring a task finished.
16
+
17
+ ## 3. Agent Prohibitions (NEVER)
18
+ - **No Shadow Changes**: Never modify code without updating the corresponding `INTENT` or `ADR` if the change is structural.
19
+ - **No Deletion without Approval**: Never delete core infrastructure or large blocks of code without explicit confirmation.
20
+ - **No Hallucinated Tech**: If an API or library is unclear, ask for clarification.
21
+
22
+ ## 4. Interaction Protocol
23
+ 1. **Read**: Check `AGENT_ONBOARDING.md` and the latest `HANDOFF`.
24
+ 2. **Plan**: Propose changes and get approval.
25
+ 3. **Execute**: Implement with tests.
26
+ 4. **Validate**: Run `levit validate`.
27
+ 5. **Handoff**: Document what was done.
28
+
29
+ ## 5. Machine-First Metadata
30
+ Agents should prioritize reading and maintaining the YAML frontmatter in all documentation files.
31
+
32
+ ---
33
+ *Status: ACTIVE | Schema: 1.1 | Last Updated: 2025-12-31*
34
+
@@ -11,14 +11,15 @@ This project is a hybrid workspace where humans define intentions and AI ensures
11
11
  ## 2. Navigation & Context
12
12
  To understand this project quickly, explore in this order:
13
13
  1. `SOCIAL_CONTRACT.md`: Your ethical and operational boundaries.
14
- 2. `features/README.md`: The roadmap and logic of what we are building.
15
- 3. `agents/AGENTS.md`: Specific definitions of other roles if they exist.
16
- 4. `.levit/workflows/`: Step-by-step guides for common tasks.
14
+ 2. `.levit/features/`: The roadmap and logic of what we are building.
15
+ 3. `.levit/decisions/`: History of technical choices (ADRs).
16
+ 4. `.levit/handoff/`: Specific context for your current mission.
17
+ 5. `.levit/workflows/`: Step-by-step guides for common tasks.
17
18
 
18
19
  ## 3. Rules of Engagement
19
20
  - **Transparency**: If you are unsure about a decision, ask the human. Do not "hallucinate" architectural choices.
20
21
  - **Atomicity**: Keep your edits small and focused.
21
- - **Traceability**: Every major change should be linked to a feature defined in `features/`.
22
+ - **Traceability**: Every major change should be linked to a feature defined in `.levit/features/`.
22
23
  - **Tests First**: Before submitting a complex change, check if tests exist in `tests/` and run them.
23
24
 
24
25
  ## 4. How to use Workflows
File without changes
@@ -1,3 +1,12 @@
1
+ ---
2
+ id: FEATURE-ID
3
+ status: active
4
+ owner: human
5
+ last_updated: 2025-01-12
6
+ risk_level: medium
7
+ depends_on: []
8
+ ---
9
+
1
10
  # INTENT: [Feature Name]
2
11
 
3
12
  > Copy this file to create a new feature specification.
@@ -3,8 +3,8 @@
3
3
  This directory contains the roadmap and the active specifications of the project.
4
4
 
5
5
  ## How to add a feature
6
- 1. Copy [INTENT.md](./INTENT.md) to a new file (e.g., `001-my-feature.md`).
7
- 2. Fill the "Human Intent" sections.
6
+ 1. Run `levit feature new` from the project root.
7
+ 2. Fill the "Human Intent" sections in the generated file.
8
8
  3. Let the Agent implement the technical details.
9
9
 
10
10
  ---
File without changes