@fermindi/pwn-cli 0.1.1 ā 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +265 -251
- package/cli/batch.js +333 -333
- package/cli/codespaces.js +303 -303
- package/cli/index.js +98 -91
- package/cli/inject.js +78 -67
- package/cli/knowledge.js +531 -531
- package/cli/migrate.js +466 -0
- package/cli/notify.js +135 -135
- package/cli/patterns.js +665 -665
- package/cli/status.js +91 -91
- package/cli/validate.js +61 -61
- package/package.json +70 -70
- package/src/core/inject.js +208 -204
- package/src/core/state.js +91 -91
- package/src/core/validate.js +202 -202
- package/src/core/workspace.js +176 -176
- package/src/index.js +20 -20
- package/src/knowledge/gc.js +308 -308
- package/src/knowledge/lifecycle.js +401 -401
- package/src/knowledge/promote.js +364 -364
- package/src/knowledge/references.js +342 -342
- package/src/patterns/matcher.js +218 -218
- package/src/patterns/registry.js +375 -375
- package/src/patterns/triggers.js +423 -423
- package/src/services/batch-service.js +849 -849
- package/src/services/notification-service.js +342 -342
- package/templates/codespaces/devcontainer.json +52 -52
- package/templates/codespaces/setup.sh +70 -70
- package/templates/workspace/.ai/README.md +164 -164
- package/templates/workspace/.ai/agents/README.md +204 -204
- package/templates/workspace/.ai/agents/claude.md +625 -625
- package/templates/workspace/.ai/config/README.md +79 -79
- package/templates/workspace/.ai/config/notifications.template.json +20 -20
- package/templates/workspace/.ai/memory/deadends.md +79 -79
- package/templates/workspace/.ai/memory/decisions.md +58 -58
- package/templates/workspace/.ai/memory/patterns.md +65 -65
- package/templates/workspace/.ai/patterns/backend/README.md +126 -126
- package/templates/workspace/.ai/patterns/frontend/README.md +103 -103
- package/templates/workspace/.ai/patterns/index.md +256 -256
- package/templates/workspace/.ai/patterns/triggers.json +1087 -1087
- package/templates/workspace/.ai/patterns/universal/README.md +141 -141
- package/templates/workspace/.ai/state.template.json +8 -8
- package/templates/workspace/.ai/tasks/active.md +77 -77
- package/templates/workspace/.ai/tasks/backlog.md +95 -95
- package/templates/workspace/.ai/workflows/batch-task.md +356 -356
package/cli/status.js
CHANGED
|
@@ -1,91 +1,91 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { getWorkspaceInfo } from '../src/core/workspace.js';
|
|
3
|
-
import { validate } from '../src/core/validate.js';
|
|
4
|
-
|
|
5
|
-
export default async function statusCommand() {
|
|
6
|
-
const info = getWorkspaceInfo();
|
|
7
|
-
|
|
8
|
-
if (!info.exists) {
|
|
9
|
-
console.log('ā No PWN workspace found\n');
|
|
10
|
-
console.log(' Run: pwn inject');
|
|
11
|
-
process.exit(1);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
// Validate workspace
|
|
15
|
-
const validation = validate();
|
|
16
|
-
|
|
17
|
-
console.log('š PWN Workspace Status\n');
|
|
18
|
-
|
|
19
|
-
// Developer info
|
|
20
|
-
if (info.state) {
|
|
21
|
-
console.log(`š¤ Developer: ${info.state.developer}`);
|
|
22
|
-
console.log(`š
Session: ${formatDate(info.state.session_started)}`);
|
|
23
|
-
if (info.state.current_task) {
|
|
24
|
-
console.log(`šÆ Task: ${info.state.current_task}`);
|
|
25
|
-
}
|
|
26
|
-
console.log();
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// Tasks summary
|
|
30
|
-
console.log('š Tasks');
|
|
31
|
-
console.log(` Active: ${info.tasks.active.pending} pending, ${info.tasks.active.completed} completed`);
|
|
32
|
-
console.log(` Backlog: ${info.tasks.backlog.total} items`);
|
|
33
|
-
console.log();
|
|
34
|
-
|
|
35
|
-
// Memory summary
|
|
36
|
-
console.log('š§ Memory');
|
|
37
|
-
console.log(` Decisions: ${info.memory.decisions}`);
|
|
38
|
-
console.log(` Patterns: ${info.memory.patterns}`);
|
|
39
|
-
console.log(` Dead-ends: ${info.memory.deadends}`);
|
|
40
|
-
console.log();
|
|
41
|
-
|
|
42
|
-
// Patterns summary
|
|
43
|
-
console.log('šØ Patterns');
|
|
44
|
-
console.log(` Triggers: ${info.patterns.triggers}`);
|
|
45
|
-
console.log(` Categories: ${info.patterns.categories.join(', ') || 'none'}`);
|
|
46
|
-
console.log();
|
|
47
|
-
|
|
48
|
-
// Validation status
|
|
49
|
-
if (validation.valid) {
|
|
50
|
-
console.log('ā
Workspace structure valid');
|
|
51
|
-
} else {
|
|
52
|
-
console.log('ā ļø Workspace has issues:');
|
|
53
|
-
for (const issue of validation.issues) {
|
|
54
|
-
console.log(` - ${issue}`);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
if (validation.warnings.length > 0) {
|
|
59
|
-
console.log('\nā ļø Warnings:');
|
|
60
|
-
for (const warning of validation.warnings) {
|
|
61
|
-
console.log(` - ${warning}`);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Format ISO date to human readable
|
|
68
|
-
* @param {string} isoDate - ISO date string
|
|
69
|
-
* @returns {string} Formatted date
|
|
70
|
-
*/
|
|
71
|
-
function formatDate(isoDate) {
|
|
72
|
-
if (!isoDate) return 'unknown';
|
|
73
|
-
|
|
74
|
-
try {
|
|
75
|
-
const date = new Date(isoDate);
|
|
76
|
-
const now = new Date();
|
|
77
|
-
const diffMs = now - date;
|
|
78
|
-
const diffMins = Math.floor(diffMs / 60000);
|
|
79
|
-
const diffHours = Math.floor(diffMs / 3600000);
|
|
80
|
-
const diffDays = Math.floor(diffMs / 86400000);
|
|
81
|
-
|
|
82
|
-
if (diffMins < 1) return 'just now';
|
|
83
|
-
if (diffMins < 60) return `${diffMins}m ago`;
|
|
84
|
-
if (diffHours < 24) return `${diffHours}h ago`;
|
|
85
|
-
if (diffDays < 7) return `${diffDays}d ago`;
|
|
86
|
-
|
|
87
|
-
return date.toLocaleDateString();
|
|
88
|
-
} catch {
|
|
89
|
-
return isoDate;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { getWorkspaceInfo } from '../src/core/workspace.js';
|
|
3
|
+
import { validate } from '../src/core/validate.js';
|
|
4
|
+
|
|
5
|
+
export default async function statusCommand() {
|
|
6
|
+
const info = getWorkspaceInfo();
|
|
7
|
+
|
|
8
|
+
if (!info.exists) {
|
|
9
|
+
console.log('ā No PWN workspace found\n');
|
|
10
|
+
console.log(' Run: pwn inject');
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Validate workspace
|
|
15
|
+
const validation = validate();
|
|
16
|
+
|
|
17
|
+
console.log('š PWN Workspace Status\n');
|
|
18
|
+
|
|
19
|
+
// Developer info
|
|
20
|
+
if (info.state) {
|
|
21
|
+
console.log(`š¤ Developer: ${info.state.developer}`);
|
|
22
|
+
console.log(`š
Session: ${formatDate(info.state.session_started)}`);
|
|
23
|
+
if (info.state.current_task) {
|
|
24
|
+
console.log(`šÆ Task: ${info.state.current_task}`);
|
|
25
|
+
}
|
|
26
|
+
console.log();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Tasks summary
|
|
30
|
+
console.log('š Tasks');
|
|
31
|
+
console.log(` Active: ${info.tasks.active.pending} pending, ${info.tasks.active.completed} completed`);
|
|
32
|
+
console.log(` Backlog: ${info.tasks.backlog.total} items`);
|
|
33
|
+
console.log();
|
|
34
|
+
|
|
35
|
+
// Memory summary
|
|
36
|
+
console.log('š§ Memory');
|
|
37
|
+
console.log(` Decisions: ${info.memory.decisions}`);
|
|
38
|
+
console.log(` Patterns: ${info.memory.patterns}`);
|
|
39
|
+
console.log(` Dead-ends: ${info.memory.deadends}`);
|
|
40
|
+
console.log();
|
|
41
|
+
|
|
42
|
+
// Patterns summary
|
|
43
|
+
console.log('šØ Patterns');
|
|
44
|
+
console.log(` Triggers: ${info.patterns.triggers}`);
|
|
45
|
+
console.log(` Categories: ${info.patterns.categories.join(', ') || 'none'}`);
|
|
46
|
+
console.log();
|
|
47
|
+
|
|
48
|
+
// Validation status
|
|
49
|
+
if (validation.valid) {
|
|
50
|
+
console.log('ā
Workspace structure valid');
|
|
51
|
+
} else {
|
|
52
|
+
console.log('ā ļø Workspace has issues:');
|
|
53
|
+
for (const issue of validation.issues) {
|
|
54
|
+
console.log(` - ${issue}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (validation.warnings.length > 0) {
|
|
59
|
+
console.log('\nā ļø Warnings:');
|
|
60
|
+
for (const warning of validation.warnings) {
|
|
61
|
+
console.log(` - ${warning}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Format ISO date to human readable
|
|
68
|
+
* @param {string} isoDate - ISO date string
|
|
69
|
+
* @returns {string} Formatted date
|
|
70
|
+
*/
|
|
71
|
+
function formatDate(isoDate) {
|
|
72
|
+
if (!isoDate) return 'unknown';
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
const date = new Date(isoDate);
|
|
76
|
+
const now = new Date();
|
|
77
|
+
const diffMs = now - date;
|
|
78
|
+
const diffMins = Math.floor(diffMs / 60000);
|
|
79
|
+
const diffHours = Math.floor(diffMs / 3600000);
|
|
80
|
+
const diffDays = Math.floor(diffMs / 86400000);
|
|
81
|
+
|
|
82
|
+
if (diffMins < 1) return 'just now';
|
|
83
|
+
if (diffMins < 60) return `${diffMins}m ago`;
|
|
84
|
+
if (diffHours < 24) return `${diffHours}h ago`;
|
|
85
|
+
if (diffDays < 7) return `${diffDays}d ago`;
|
|
86
|
+
|
|
87
|
+
return date.toLocaleDateString();
|
|
88
|
+
} catch {
|
|
89
|
+
return isoDate;
|
|
90
|
+
}
|
|
91
|
+
}
|
package/cli/validate.js
CHANGED
|
@@ -1,61 +1,61 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { validate, getStructureReport } from '../src/core/validate.js';
|
|
3
|
-
|
|
4
|
-
export default async function validateCommand(args = []) {
|
|
5
|
-
const verbose = args.includes('--verbose') || args.includes('-v');
|
|
6
|
-
|
|
7
|
-
console.log('š Validating PWN workspace...\n');
|
|
8
|
-
|
|
9
|
-
const result = validate();
|
|
10
|
-
|
|
11
|
-
if (verbose) {
|
|
12
|
-
const report = getStructureReport();
|
|
13
|
-
console.log('š Structure Report:\n');
|
|
14
|
-
|
|
15
|
-
console.log(' Directories:');
|
|
16
|
-
for (const [dir, exists] of Object.entries(report.directories)) {
|
|
17
|
-
const icon = exists ? 'ā' : 'ā';
|
|
18
|
-
console.log(` ${icon} .ai/${dir}/`);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
console.log('\n Files:');
|
|
22
|
-
for (const [file, exists] of Object.entries(report.files)) {
|
|
23
|
-
const icon = exists ? 'ā' : 'ā';
|
|
24
|
-
console.log(` ${icon} .ai/${file}`);
|
|
25
|
-
}
|
|
26
|
-
console.log();
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (result.valid) {
|
|
30
|
-
console.log('ā
Workspace is valid\n');
|
|
31
|
-
|
|
32
|
-
if (result.warnings.length > 0) {
|
|
33
|
-
console.log('ā ļø Warnings:');
|
|
34
|
-
for (const warning of result.warnings) {
|
|
35
|
-
console.log(` - ${warning}`);
|
|
36
|
-
}
|
|
37
|
-
console.log();
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
process.exit(0);
|
|
41
|
-
} else {
|
|
42
|
-
console.log('ā Workspace has issues:\n');
|
|
43
|
-
|
|
44
|
-
for (const issue of result.issues) {
|
|
45
|
-
console.log(` ā ${issue}`);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (result.warnings.length > 0) {
|
|
49
|
-
console.log('\nā ļø Warnings:');
|
|
50
|
-
for (const warning of result.warnings) {
|
|
51
|
-
console.log(` - ${warning}`);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
console.log('\nš” To fix, try:');
|
|
56
|
-
console.log(' pwn inject --force (recreate workspace)');
|
|
57
|
-
console.log();
|
|
58
|
-
|
|
59
|
-
process.exit(1);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { validate, getStructureReport } from '../src/core/validate.js';
|
|
3
|
+
|
|
4
|
+
export default async function validateCommand(args = []) {
|
|
5
|
+
const verbose = args.includes('--verbose') || args.includes('-v');
|
|
6
|
+
|
|
7
|
+
console.log('š Validating PWN workspace...\n');
|
|
8
|
+
|
|
9
|
+
const result = validate();
|
|
10
|
+
|
|
11
|
+
if (verbose) {
|
|
12
|
+
const report = getStructureReport();
|
|
13
|
+
console.log('š Structure Report:\n');
|
|
14
|
+
|
|
15
|
+
console.log(' Directories:');
|
|
16
|
+
for (const [dir, exists] of Object.entries(report.directories)) {
|
|
17
|
+
const icon = exists ? 'ā' : 'ā';
|
|
18
|
+
console.log(` ${icon} .ai/${dir}/`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
console.log('\n Files:');
|
|
22
|
+
for (const [file, exists] of Object.entries(report.files)) {
|
|
23
|
+
const icon = exists ? 'ā' : 'ā';
|
|
24
|
+
console.log(` ${icon} .ai/${file}`);
|
|
25
|
+
}
|
|
26
|
+
console.log();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (result.valid) {
|
|
30
|
+
console.log('ā
Workspace is valid\n');
|
|
31
|
+
|
|
32
|
+
if (result.warnings.length > 0) {
|
|
33
|
+
console.log('ā ļø Warnings:');
|
|
34
|
+
for (const warning of result.warnings) {
|
|
35
|
+
console.log(` - ${warning}`);
|
|
36
|
+
}
|
|
37
|
+
console.log();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
process.exit(0);
|
|
41
|
+
} else {
|
|
42
|
+
console.log('ā Workspace has issues:\n');
|
|
43
|
+
|
|
44
|
+
for (const issue of result.issues) {
|
|
45
|
+
console.log(` ā ${issue}`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (result.warnings.length > 0) {
|
|
49
|
+
console.log('\nā ļø Warnings:');
|
|
50
|
+
for (const warning of result.warnings) {
|
|
51
|
+
console.log(` - ${warning}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
console.log('\nš” To fix, try:');
|
|
56
|
+
console.log(' pwn inject --force (recreate workspace)');
|
|
57
|
+
console.log();
|
|
58
|
+
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
}
|
package/package.json
CHANGED
|
@@ -1,70 +1,70 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@fermindi/pwn-cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Professional AI Workspace - Inject structured memory and automation into any project for AI-powered development",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"bin": {
|
|
7
|
-
"pwn": "./cli/index.js"
|
|
8
|
-
},
|
|
9
|
-
"main": "./src/index.js",
|
|
10
|
-
"exports": {
|
|
11
|
-
".": "./src/index.js",
|
|
12
|
-
"./core/state": "./src/core/state.js",
|
|
13
|
-
"./core/inject": "./src/core/inject.js",
|
|
14
|
-
"./core/validate": "./src/core/validate.js",
|
|
15
|
-
"./core/workspace": "./src/core/workspace.js",
|
|
16
|
-
"./services/batch": "./src/services/batch-service.js",
|
|
17
|
-
"./services/notifications": "./src/services/notification-service.js",
|
|
18
|
-
"./patterns/registry": "./src/patterns/registry.js",
|
|
19
|
-
"./patterns/triggers": "./src/patterns/triggers.js",
|
|
20
|
-
"./knowledge/lifecycle": "./src/knowledge/lifecycle.js",
|
|
21
|
-
"./knowledge/references": "./src/knowledge/references.js",
|
|
22
|
-
"./knowledge/gc": "./src/knowledge/gc.js",
|
|
23
|
-
"./knowledge/promote": "./src/knowledge/promote.js"
|
|
24
|
-
},
|
|
25
|
-
"files": [
|
|
26
|
-
"cli/",
|
|
27
|
-
"src/",
|
|
28
|
-
"templates/",
|
|
29
|
-
"README.md",
|
|
30
|
-
"LICENSE"
|
|
31
|
-
],
|
|
32
|
-
"scripts": {
|
|
33
|
-
"start": "node cli/index.js",
|
|
34
|
-
"dev": "node --watch cli/index.js",
|
|
35
|
-
"test": "vitest run",
|
|
36
|
-
"test:watch": "vitest",
|
|
37
|
-
"test:coverage": "vitest run --coverage",
|
|
38
|
-
"prepublishOnly": "npm test"
|
|
39
|
-
},
|
|
40
|
-
"keywords": [
|
|
41
|
-
"ai",
|
|
42
|
-
"cli",
|
|
43
|
-
"workspace",
|
|
44
|
-
"automation",
|
|
45
|
-
"claude",
|
|
46
|
-
"patterns",
|
|
47
|
-
"memory",
|
|
48
|
-
"decisions",
|
|
49
|
-
"batch",
|
|
50
|
-
"codespaces",
|
|
51
|
-
"developer-tools",
|
|
52
|
-
"productivity"
|
|
53
|
-
],
|
|
54
|
-
"author": "Diego Fernandes",
|
|
55
|
-
"license": "MIT",
|
|
56
|
-
"repository": {
|
|
57
|
-
"type": "git",
|
|
58
|
-
"url": "git+https://github.com/fermindi/pwn.git"
|
|
59
|
-
},
|
|
60
|
-
"bugs": {
|
|
61
|
-
"url": "https://github.com/fermindi/pwn/issues"
|
|
62
|
-
},
|
|
63
|
-
"homepage": "https://github.com/fermindi/pwn#readme",
|
|
64
|
-
"engines": {
|
|
65
|
-
"node": ">=18.0.0"
|
|
66
|
-
},
|
|
67
|
-
"devDependencies": {
|
|
68
|
-
"vitest": "^2.0.0"
|
|
69
|
-
}
|
|
70
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@fermindi/pwn-cli",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Professional AI Workspace - Inject structured memory and automation into any project for AI-powered development",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"pwn": "./cli/index.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "./src/index.js",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": "./src/index.js",
|
|
12
|
+
"./core/state": "./src/core/state.js",
|
|
13
|
+
"./core/inject": "./src/core/inject.js",
|
|
14
|
+
"./core/validate": "./src/core/validate.js",
|
|
15
|
+
"./core/workspace": "./src/core/workspace.js",
|
|
16
|
+
"./services/batch": "./src/services/batch-service.js",
|
|
17
|
+
"./services/notifications": "./src/services/notification-service.js",
|
|
18
|
+
"./patterns/registry": "./src/patterns/registry.js",
|
|
19
|
+
"./patterns/triggers": "./src/patterns/triggers.js",
|
|
20
|
+
"./knowledge/lifecycle": "./src/knowledge/lifecycle.js",
|
|
21
|
+
"./knowledge/references": "./src/knowledge/references.js",
|
|
22
|
+
"./knowledge/gc": "./src/knowledge/gc.js",
|
|
23
|
+
"./knowledge/promote": "./src/knowledge/promote.js"
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"cli/",
|
|
27
|
+
"src/",
|
|
28
|
+
"templates/",
|
|
29
|
+
"README.md",
|
|
30
|
+
"LICENSE"
|
|
31
|
+
],
|
|
32
|
+
"scripts": {
|
|
33
|
+
"start": "node cli/index.js",
|
|
34
|
+
"dev": "node --watch cli/index.js",
|
|
35
|
+
"test": "vitest run",
|
|
36
|
+
"test:watch": "vitest",
|
|
37
|
+
"test:coverage": "vitest run --coverage",
|
|
38
|
+
"prepublishOnly": "npm test"
|
|
39
|
+
},
|
|
40
|
+
"keywords": [
|
|
41
|
+
"ai",
|
|
42
|
+
"cli",
|
|
43
|
+
"workspace",
|
|
44
|
+
"automation",
|
|
45
|
+
"claude",
|
|
46
|
+
"patterns",
|
|
47
|
+
"memory",
|
|
48
|
+
"decisions",
|
|
49
|
+
"batch",
|
|
50
|
+
"codespaces",
|
|
51
|
+
"developer-tools",
|
|
52
|
+
"productivity"
|
|
53
|
+
],
|
|
54
|
+
"author": "Diego Fernandes",
|
|
55
|
+
"license": "MIT",
|
|
56
|
+
"repository": {
|
|
57
|
+
"type": "git",
|
|
58
|
+
"url": "git+https://github.com/fermindi/pwn.git"
|
|
59
|
+
},
|
|
60
|
+
"bugs": {
|
|
61
|
+
"url": "https://github.com/fermindi/pwn/issues"
|
|
62
|
+
},
|
|
63
|
+
"homepage": "https://github.com/fermindi/pwn#readme",
|
|
64
|
+
"engines": {
|
|
65
|
+
"node": ">=18.0.0"
|
|
66
|
+
},
|
|
67
|
+
"devDependencies": {
|
|
68
|
+
"vitest": "^2.0.0"
|
|
69
|
+
}
|
|
70
|
+
}
|