@acmecloud/core 1.0.5 → 1.0.7

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.
@@ -0,0 +1,119 @@
1
+ ---
2
+ name: windows-shell-guide
3
+ description: Windows PowerShell command reference - use on Windows instead of Unix commands
4
+ ---
5
+
6
+ # Windows Shell Guide
7
+
8
+ **Use when OS is Windows (win32)**
9
+
10
+ ## Forbidden Commands on Windows
11
+
12
+ **DO NOT use:**
13
+ `head`, `tail`, `grep`, `sed`, `awk`, `xargs`, `wc`, `ls`, `cp`, `mv`, `rm`, `ps`, `kill`, `chmod`, `chown`
14
+
15
+ ## Quick Reference
16
+
17
+ | Need | PowerShell Command |
18
+ | -------------- | ------------------------------------ |
19
+ | View file | `Get-Content file` |
20
+ | First N lines | `Get-Content file -Head N` |
21
+ | Last N lines | `Get-Content file -Tail N` |
22
+ | Search text | `Select-String "pattern" file` |
23
+ | Count lines | `(Get-Content file).Count` |
24
+ | List files | `Get-ChildItem` |
25
+ | Copy file | `Copy-Item src dest` |
26
+ | Move file | `Move-Item src dest` |
27
+ | Delete file | `Remove-Item file -Force` |
28
+ | Delete folder | `Remove-Item folder -Recurse -Force` |
29
+ | List processes | `Get-Process` |
30
+ | Kill process | `Stop-Process -Id PID -Force` |
31
+
32
+ ## Common Patterns
33
+
34
+ ### File Operations
35
+
36
+ ```powershell
37
+ # Read file
38
+ Get-Content file.txt
39
+
40
+ # Search in file
41
+ Select-String "error" file.txt
42
+
43
+ # Count lines
44
+ (Get-Content file.txt).Count
45
+
46
+ # Find files
47
+ Get-ChildItem -Filter "*.py" -Recurse
48
+
49
+ # Delete with force
50
+ Remove-Item file.txt -Force
51
+ Remove-Item folder -Recurse -Force
52
+ ```
53
+
54
+ ### Process Management
55
+
56
+ ```powershell
57
+ # List processes
58
+ Get-Process python
59
+
60
+ # Kill process
61
+ Stop-Process -Id 1234 -Force
62
+
63
+ # Filter processes
64
+ Get-Process | Where-Object {$_.Name -like "python"}
65
+ ```
66
+
67
+ ### Pipes and Filtering
68
+
69
+ ```powershell
70
+ # Find files > 1MB
71
+ Get-ChildItem -Recurse | Where-Object {$_.Length -gt 1MB}
72
+
73
+ # Search in multiple files
74
+ Get-ChildItem -Filter "*.log" | Select-String "ERROR"
75
+
76
+ # Get top 5 by CPU
77
+ Get-Process | Sort-Object CPU -Descending | Select-Object -First 5
78
+ ```
79
+
80
+ ## Common Mistakes
81
+
82
+ | Unix (DON'T) | PowerShell (DO) |
83
+ | ------------------- | ------------------------------------ |
84
+ | `head file.txt` | `Get-Content file.txt -Head 10` |
85
+ | `grep "pattern"` | `Select-String "pattern"` |
86
+ | `cat file \| wc -l` | `(Get-Content file).Count` |
87
+ | `rm -rf folder` | `Remove-Item folder -Recurse -Force` |
88
+ | `ls -la` | `Get-ChildItem` |
89
+
90
+ ## Safe Execution
91
+
92
+ ```powershell
93
+ # Dry run (preview changes)
94
+ Get-ChildItem folder -Recurse -WhatIf
95
+
96
+ # Check before delete
97
+ if (Test-Path file.txt) { Remove-Item file.txt }
98
+
99
+ # Suppress errors
100
+ Get-Content file.txt -ErrorAction SilentlyContinue
101
+ ```
102
+
103
+ ## Common Parameters
104
+
105
+ - `-WhatIf` - Preview changes
106
+ - `-Confirm` - Prompt before execution
107
+ - `-ErrorAction` - Stop, SilentlyContinue, Continue
108
+ - `-Verbose` - Detailed output
109
+ - `-Recurse` - Include subdirectories
110
+ - `-Force` - Override restrictions
111
+
112
+ ## Key Principles
113
+
114
+ 1. Always check OS first
115
+ 2. Use PowerShell Verb-Noun syntax
116
+ 3. Reference this guide before guessing
117
+ 4. Test dangerous operations with `-WhatIf`
118
+
119
+ **Stop errors before they happen:** Check OS, read guide, execute correctly.
@@ -1,86 +1,141 @@
1
- import * as fs from 'fs/promises';
2
- import path from 'path';
3
- import os from 'os';
4
-
5
- export interface Skill {
6
- name: string;
7
- description: string;
8
- content: string;
9
- }
10
-
11
- /**
12
- * Searches upward from startDir for the given targets.
13
- */
14
- async function findUpDirectories(startDir: string, targets: string[]): Promise<string[]> {
15
- const results: string[] = [];
16
- let current = path.resolve(startDir);
17
- const root = path.parse(current).root;
18
-
19
- while (true) {
20
- for (const target of targets) {
21
- const fullPath = path.join(current, target);
22
- try {
23
- const stat = await fs.stat(fullPath);
24
- if (stat.isDirectory()) {
25
- results.push(fullPath);
26
- }
27
- } catch {
28
- // Ignore
29
- }
30
- }
31
- if (current === root) break;
32
- current = path.dirname(current);
33
- }
34
- return results;
35
- }
36
-
37
- export async function loadSkills(): Promise<Skill[]> {
38
- const globalSkillsPath = path.join(os.homedir(), '.acmecode', 'skills');
39
-
40
- // OpenCode patterns: .agents/skills, .claude/skills, .acmecode/skills
41
- const searchTargets = [
42
- '.acmecode/skills',
43
- '.agents/skills',
44
- '.claude/skills',
45
- ];
46
-
47
- const localSkillDirs = await findUpDirectories(process.cwd(), searchTargets);
48
-
49
- // Priority: Lower directories in the tree (closer to project root) are processed first,
50
- // and higher directories (closer to CWD) are processed last to overwrite.
51
- // Global is processed first of all.
52
- const allDirs = [globalSkillsPath, ...localSkillDirs.reverse()];
53
- const skillsMap = new Map<string, Skill>();
54
-
55
- for (const dir of allDirs) {
56
- try {
57
- const files = await fs.readdir(dir);
58
- for (const file of files) {
59
- if (file.endsWith('.md')) {
60
- const content = await fs.readFile(path.join(dir, file), 'utf8');
61
- let name = file.replace('.md', '');
62
-
63
- // Improved parsing: Look for name and description in YAML frontmatter or content
64
- let description = `Skill ${name}`;
65
-
66
- // Try to extract name from frontmatter
67
- const nameMatch = content.match(/^name:\s*(.*)/m);
68
- if (nameMatch) name = nameMatch[1].trim();
69
-
70
- const descriptionMatch = content.match(/^description:\s*(.*)/m);
71
- if (descriptionMatch) {
72
- description = descriptionMatch[1].trim();
73
- }
74
-
75
- skillsMap.set(name, { name, description, content });
76
- }
77
- }
78
- } catch (err: any) {
79
- if (err.code !== 'ENOENT') {
80
- console.warn(`Could not read skills directory ${dir}: ${err.message}`);
81
- }
82
- }
83
- }
84
-
85
- return Array.from(skillsMap.values());
86
- }
1
+ import * as fs from "fs/promises";
2
+ import path from "path";
3
+ import os from "os";
4
+ import { fileURLToPath } from "url";
5
+ import { dirname } from "path";
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = dirname(__filename);
9
+
10
+ export interface Skill {
11
+ name: string;
12
+ description: string;
13
+ content: string;
14
+ }
15
+
16
+ /**
17
+ * Load built-in skills from the builtin directory
18
+ */
19
+ async function loadBuiltinSkills(): Promise<Skill[]> {
20
+ const builtinSkillsDir = path.join(__dirname, "builtin");
21
+ const skills: Skill[] = [];
22
+
23
+ try {
24
+ const files = await fs.readdir(builtinSkillsDir);
25
+ for (const file of files) {
26
+ if (file.endsWith(".md")) {
27
+ const filePath = path.join(builtinSkillsDir, file);
28
+ const content = await fs.readFile(filePath, "utf8");
29
+ let name = file.replace(".md", "");
30
+ let description = `Skill ${name}`;
31
+
32
+ // Extract name from frontmatter
33
+ const nameMatch = content.match(/^---[\r\n]+name:\s*(.*)/m);
34
+ if (nameMatch) {
35
+ name = nameMatch[1].trim();
36
+ }
37
+
38
+ // Extract description from frontmatter
39
+ const descriptionMatch = content.match(/^description:\s*(.*)/m);
40
+ if (descriptionMatch) {
41
+ description = descriptionMatch[1].trim();
42
+ }
43
+
44
+ skills.push({ name, description, content });
45
+ }
46
+ }
47
+ } catch (err: any) {
48
+ if (err.code !== "ENOENT") {
49
+ console.warn(`Could not read builtin skills: ${err.message}`);
50
+ }
51
+ }
52
+
53
+ return skills;
54
+ }
55
+
56
+ /**
57
+ * Searches upward from startDir for the given targets.
58
+ */
59
+ async function findUpDirectories(
60
+ startDir: string,
61
+ targets: string[],
62
+ ): Promise<string[]> {
63
+ const results: string[] = [];
64
+ let current = path.resolve(startDir);
65
+ const root = path.parse(current).root;
66
+
67
+ while (true) {
68
+ for (const target of targets) {
69
+ const fullPath = path.join(current, target);
70
+ try {
71
+ const stat = await fs.stat(fullPath);
72
+ if (stat.isDirectory()) {
73
+ results.push(fullPath);
74
+ }
75
+ } catch {
76
+ // Ignore
77
+ }
78
+ }
79
+ if (current === root) break;
80
+ current = path.dirname(current);
81
+ }
82
+ return results;
83
+ }
84
+
85
+ export async function loadSkills(): Promise<Skill[]> {
86
+ const globalSkillsPath = path.join(os.homedir(), ".acmecode", "skills");
87
+
88
+ // OpenCode patterns: .agents/skills, .claude/skills, .acmecode/skills
89
+ const searchTargets = [
90
+ ".acmecode/skills",
91
+ ".agents/skills",
92
+ ".claude/skills",
93
+ ];
94
+
95
+ const localSkillDirs = await findUpDirectories(process.cwd(), searchTargets);
96
+
97
+ // Priority: Lower directories in the tree (closer to project root) are processed first,
98
+ // and higher directories (closer to CWD) are processed last to overwrite.
99
+ // Global is processed first of all.
100
+ const allDirs = [globalSkillsPath, ...localSkillDirs.reverse()];
101
+ const skillsMap = new Map<string, Skill>();
102
+
103
+ // First, load built-in skills
104
+ const builtinSkills = await loadBuiltinSkills();
105
+ for (const skill of builtinSkills) {
106
+ skillsMap.set(skill.name, skill);
107
+ }
108
+
109
+ // Then load user skills (can override built-ins)
110
+ for (const dir of allDirs) {
111
+ try {
112
+ const files = await fs.readdir(dir);
113
+ for (const file of files) {
114
+ if (file.endsWith(".md")) {
115
+ const content = await fs.readFile(path.join(dir, file), "utf8");
116
+ let name = file.replace(".md", "");
117
+
118
+ // Improved parsing: Look for name and description in YAML frontmatter or content
119
+ let description = `Skill ${name}`;
120
+
121
+ // Try to extract name from frontmatter
122
+ const nameMatch = content.match(/^name:\s*(.*)/m);
123
+ if (nameMatch) name = nameMatch[1].trim();
124
+
125
+ const descriptionMatch = content.match(/^description:\s*(.*)/m);
126
+ if (descriptionMatch) {
127
+ description = descriptionMatch[1].trim();
128
+ }
129
+
130
+ skillsMap.set(name, { name, description, content });
131
+ }
132
+ }
133
+ } catch (err: any) {
134
+ if (err.code !== "ENOENT") {
135
+ console.warn(`Could not read skills directory ${dir}: ${err.message}`);
136
+ }
137
+ }
138
+ }
139
+
140
+ return Array.from(skillsMap.values());
141
+ }