@codeflyai/codefly 0.24.1 → 0.24.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 (48) hide show
  1. package/bundle/builtin/skill-creator/SKILL.md +382 -0
  2. package/bundle/builtin/skill-creator/scripts/init_skill.cjs +235 -0
  3. package/bundle/builtin/skill-creator/scripts/package_skill.cjs +102 -0
  4. package/bundle/builtin/skill-creator/scripts/validate_skill.cjs +127 -0
  5. package/bundle/codefly.js +296592 -296367
  6. package/bundle/docs/architecture.md +3 -3
  7. package/bundle/docs/assets/monitoring-dashboard-logs.png +0 -0
  8. package/bundle/docs/assets/monitoring-dashboard-metrics.png +0 -0
  9. package/bundle/docs/assets/monitoring-dashboard-overview.png +0 -0
  10. package/bundle/docs/changelogs/index.md +134 -0
  11. package/bundle/docs/changelogs/latest.md +355 -210
  12. package/bundle/docs/changelogs/preview.md +318 -115
  13. package/bundle/docs/cli/commands.md +21 -0
  14. package/bundle/docs/cli/custom-commands.md +9 -9
  15. package/bundle/docs/cli/index.md +6 -2
  16. package/bundle/docs/cli/keyboard-shortcuts.md +61 -78
  17. package/bundle/docs/cli/model-routing.md +7 -2
  18. package/bundle/docs/cli/model.md +1 -1
  19. package/bundle/docs/cli/openspec.md +164 -0
  20. package/bundle/docs/cli/sandbox.md +1 -1
  21. package/bundle/docs/cli/settings.md +80 -60
  22. package/bundle/docs/cli/skills.md +188 -0
  23. package/bundle/docs/cli/system-prompt.md +32 -0
  24. package/bundle/docs/cli/telemetry.md +38 -3
  25. package/bundle/docs/cli/themes.md +0 -2
  26. package/bundle/docs/cli/tutorials/skills-getting-started.md +124 -0
  27. package/bundle/docs/cli/tutorials.md +4 -0
  28. package/bundle/docs/core/index.md +4 -0
  29. package/bundle/docs/core/memport.md +2 -0
  30. package/bundle/docs/core/policy-engine.md +3 -2
  31. package/bundle/docs/extensions/getting-started-extensions.md +39 -2
  32. package/bundle/docs/get-started/configuration.md +130 -74
  33. package/bundle/docs/get-started/gemini-3.md +2 -17
  34. package/bundle/docs/hooks/reference.md +245 -116
  35. package/bundle/docs/index.md +2 -0
  36. package/bundle/docs/local-development.md +1 -1
  37. package/bundle/docs/releases.md +1 -1
  38. package/bundle/docs/sidebar.json +5 -5
  39. package/bundle/docs/tools/index.md +3 -0
  40. package/bundle/docs/tools/mcp-server.md +26 -2
  41. package/bundle/docs/tools/shell.md +1 -1
  42. package/bundle/docs/troubleshooting.md +23 -5
  43. package/bundle/policies/agent.toml +1 -1
  44. package/bundle/policies/plan.toml +70 -0
  45. package/bundle/policies/read-only.toml +0 -5
  46. package/bundle/policies/yolo.toml +1 -0
  47. package/package.json +10 -5
  48. package/bundle/docs/get-started/deployment.md +0 -143
@@ -0,0 +1,102 @@
1
+ #!/usr/bin/env node
2
+
3
+ /* eslint-env node */
4
+
5
+ /**
6
+ * Skill Packager - Creates a distributable .skill file of a skill folder
7
+ *
8
+ * Usage:
9
+ * node package_skill.js <path/to/skill-folder> [output-directory]
10
+ */
11
+
12
+ const path = require('node:path');
13
+ const { spawnSync } = require('node:child_process');
14
+ const { validateSkill } = require('./validate_skill.cjs');
15
+
16
+ async function main() {
17
+ const args = process.argv.slice(2);
18
+ if (args.length < 1) {
19
+ console.log(
20
+ 'Usage: node package_skill.js <path/to/skill-folder> [output-directory]',
21
+ );
22
+ process.exit(1);
23
+ }
24
+
25
+ const skillPathArg = args[0];
26
+ const outputDirArg = args[1];
27
+
28
+ if (
29
+ skillPathArg.includes('..') ||
30
+ (outputDirArg && outputDirArg.includes('..'))
31
+ ) {
32
+ console.error('❌ Error: Path traversal detected in arguments.');
33
+ process.exit(1);
34
+ }
35
+
36
+ const skillPath = path.resolve(skillPathArg);
37
+ const outputDir = outputDirArg ? path.resolve(outputDirArg) : process.cwd();
38
+ const skillName = path.basename(skillPath);
39
+
40
+ // 1. Validate first
41
+ console.log('🔍 Validating skill...');
42
+ const result = validateSkill(skillPath);
43
+ if (!result.valid) {
44
+ console.error(`❌ Validation failed: ${result.message}`);
45
+ process.exit(1);
46
+ }
47
+
48
+ if (result.warning) {
49
+ console.warn(`⚠️ ${result.warning}`);
50
+ console.log('Please resolve all TODOs before packaging.');
51
+ process.exit(1);
52
+ }
53
+ console.log('✅ Skill is valid!');
54
+
55
+ // 2. Package
56
+ const outputFilename = path.join(outputDir, `${skillName}.skill`);
57
+
58
+ try {
59
+ // Zip everything except junk, keeping the folder structure
60
+ // We'll use the native 'zip' command for simplicity in a CLI environment
61
+ // or we could use a JS library, but zip is ubiquitous on darwin/linux.
62
+
63
+ // Command to zip:
64
+ // -r: recursive
65
+ // -x: exclude patterns
66
+ // Run the zip command from within the directory to avoid parent folder nesting
67
+ let zipProcess = spawnSync('zip', ['-r', outputFilename, '.'], {
68
+ cwd: skillPath,
69
+ stdio: 'inherit',
70
+ });
71
+
72
+ if (zipProcess.error || zipProcess.status !== 0) {
73
+ // Fallback to tar --format=zip if zip is not available (common on Windows)
74
+ console.log('zip command not found, falling back to tar...');
75
+ zipProcess = spawnSync(
76
+ 'tar',
77
+ ['-a', '-c', '--format=zip', '-f', outputFilename, '.'],
78
+ {
79
+ cwd: skillPath,
80
+ stdio: 'inherit',
81
+ },
82
+ );
83
+ }
84
+
85
+ if (zipProcess.error) {
86
+ throw zipProcess.error;
87
+ }
88
+
89
+ if (zipProcess.status !== 0) {
90
+ throw new Error(
91
+ `Packaging command failed with exit code ${zipProcess.status}`,
92
+ );
93
+ }
94
+
95
+ console.log(`✅ Successfully packaged skill to: ${outputFilename}`);
96
+ } catch (err) {
97
+ console.error(`❌ Error packaging: ${err.message}`);
98
+ process.exit(1);
99
+ }
100
+ }
101
+
102
+ main();
@@ -0,0 +1,127 @@
1
+ /* eslint-env node */
2
+
3
+ /**
4
+ * Quick validation logic for skills.
5
+ * Leveraging existing dependencies when possible or providing a zero-dep fallback.
6
+ */
7
+
8
+ const fs = require('node:fs');
9
+ const path = require('node:path');
10
+
11
+ function validateSkill(skillPath) {
12
+ if (!fs.existsSync(skillPath) || !fs.statSync(skillPath).isDirectory()) {
13
+ return { valid: false, message: `Path is not a directory: ${skillPath}` };
14
+ }
15
+
16
+ const skillMdPath = path.join(skillPath, 'SKILL.md');
17
+ if (!fs.existsSync(skillMdPath)) {
18
+ return { valid: false, message: 'SKILL.md not found' };
19
+ }
20
+
21
+ const content = fs.readFileSync(skillMdPath, 'utf8');
22
+ if (!content.startsWith('---')) {
23
+ return { valid: false, message: 'No YAML frontmatter found' };
24
+ }
25
+
26
+ const parts = content.split('---');
27
+ if (parts.length < 3) {
28
+ return { valid: false, message: 'Invalid frontmatter format' };
29
+ }
30
+
31
+ const frontmatterText = parts[1];
32
+
33
+ const nameMatch = frontmatterText.match(/^name:\s*(.+)$/m);
34
+ // Match description: "text" or description: 'text' or description: text
35
+ const descMatch = frontmatterText.match(
36
+ /^description:\s*(?:'([^']*)'|"([^"]*)"|(.+))$/m,
37
+ );
38
+
39
+ if (!nameMatch)
40
+ return { valid: false, message: 'Missing "name" in frontmatter' };
41
+ if (!descMatch)
42
+ return {
43
+ valid: false,
44
+ message: 'Description must be a single-line string: description: ...',
45
+ };
46
+
47
+ const name = nameMatch[1].trim();
48
+ const description = (
49
+ descMatch[1] !== undefined
50
+ ? descMatch[1]
51
+ : descMatch[2] !== undefined
52
+ ? descMatch[2]
53
+ : descMatch[3] || ''
54
+ ).trim();
55
+
56
+ if (description.includes('\n')) {
57
+ return {
58
+ valid: false,
59
+ message: 'Description must be a single line (no newlines)',
60
+ };
61
+ }
62
+
63
+ if (!/^[a-z0-9-]+$/.test(name)) {
64
+ return { valid: false, message: `Name "${name}" should be hyphen-case` };
65
+ }
66
+
67
+ if (description.length > 1024) {
68
+ return { valid: false, message: 'Description is too long (max 1024)' };
69
+ }
70
+
71
+ // Check for TODOs
72
+ const files = getAllFiles(skillPath);
73
+ for (const file of files) {
74
+ const fileContent = fs.readFileSync(file, 'utf8');
75
+ if (fileContent.includes('TODO:')) {
76
+ return {
77
+ valid: true,
78
+ message: 'Skill has unresolved TODOs',
79
+ warning: `Found unresolved TODO in ${path.relative(skillPath, file)}`,
80
+ };
81
+ }
82
+ }
83
+
84
+ return { valid: true, message: 'Skill is valid!' };
85
+ }
86
+
87
+ function getAllFiles(dir, fileList = []) {
88
+ const files = fs.readdirSync(dir);
89
+ files.forEach((file) => {
90
+ const name = path.join(dir, file);
91
+ if (fs.statSync(name).isDirectory()) {
92
+ if (!['node_modules', '.git', '__pycache__'].includes(file)) {
93
+ getAllFiles(name, fileList);
94
+ }
95
+ } else {
96
+ fileList.push(name);
97
+ }
98
+ });
99
+ return fileList;
100
+ }
101
+
102
+ if (require.main === module) {
103
+ const args = process.argv.slice(2);
104
+ if (args.length !== 1) {
105
+ console.log('Usage: node validate_skill.js <skill_directory>');
106
+ process.exit(1);
107
+ }
108
+
109
+ const skillDirArg = args[0];
110
+ if (skillDirArg.includes('..')) {
111
+ console.error('❌ Error: Path traversal detected in skill directory path.');
112
+ process.exit(1);
113
+ }
114
+
115
+ const result = validateSkill(path.resolve(skillDirArg));
116
+ if (result.warning) {
117
+ console.warn(`⚠️ ${result.warning}`);
118
+ }
119
+ if (result.valid) {
120
+ console.log(`✅ ${result.message}`);
121
+ } else {
122
+ console.error(`❌ ${result.message}`);
123
+ process.exit(1);
124
+ }
125
+ }
126
+
127
+ module.exports = { validateSkill };