skillo 0.2.6 → 0.2.9

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 (68) hide show
  1. package/README.md +198 -198
  2. package/dist/api-client-BF6GDR7Q.js +12 -0
  3. package/dist/{chunk-WJKZWKER.js → chunk-63FVALWX.js} +1 -1
  4. package/dist/chunk-63FVALWX.js.map +1 -0
  5. package/dist/chunk-6GOJPFZ7.js +113 -0
  6. package/dist/chunk-6GOJPFZ7.js.map +1 -0
  7. package/dist/chunk-6UGTWBUW.js +89 -0
  8. package/dist/chunk-6UGTWBUW.js.map +1 -0
  9. package/dist/{chunk-2CVEPT6U.js → chunk-73NUWYUO.js} +2 -2
  10. package/dist/chunk-73NUWYUO.js.map +1 -0
  11. package/dist/chunk-QIV4VIXA.js +221 -0
  12. package/dist/chunk-QIV4VIXA.js.map +1 -0
  13. package/dist/{chunk-CPL3P2OF.js → chunk-QUXHHRRK.js} +2 -2
  14. package/dist/chunk-QUXHHRRK.js.map +1 -0
  15. package/dist/{chunk-ODOZM4QV.js → chunk-RQ2SC5HW.js} +72 -10
  16. package/dist/chunk-RQ2SC5HW.js.map +1 -0
  17. package/dist/chunk-U53QWUOR.js +727 -0
  18. package/dist/chunk-U53QWUOR.js.map +1 -0
  19. package/dist/chunk-VAQ73XPE.js +68 -0
  20. package/dist/chunk-VAQ73XPE.js.map +1 -0
  21. package/dist/chunk-XLJGCOVT.js +975 -0
  22. package/dist/chunk-XLJGCOVT.js.map +1 -0
  23. package/dist/{claude-watcher-N6GN6WHJ.js → claude-watcher-WKGBJYKN.js} +65 -3
  24. package/dist/claude-watcher-WKGBJYKN.js.map +1 -0
  25. package/dist/cli.js +495 -1846
  26. package/dist/cli.js.map +1 -1
  27. package/dist/{config-P5EM5L7N.js → config-ZOKAP2LJ.js} +3 -3
  28. package/dist/daemon-6DTCMOJB.js +28 -0
  29. package/dist/daemon-runner.js +338 -71
  30. package/dist/daemon-runner.js.map +1 -1
  31. package/dist/database-KQY5OSCS.js +9 -0
  32. package/dist/git-OGUSYBJS.js +16 -0
  33. package/dist/git-OGUSYBJS.js.map +1 -0
  34. package/dist/git-OUAHIOY2.js +110 -0
  35. package/dist/git-OUAHIOY2.js.map +1 -0
  36. package/dist/index.js.map +1 -1
  37. package/dist/{paths-INOKEM66.js → paths-MPOZBOKE.js} +2 -2
  38. package/dist/paths-MPOZBOKE.js.map +1 -0
  39. package/dist/project-OFU2W6MH.js +19 -0
  40. package/dist/project-OFU2W6MH.js.map +1 -0
  41. package/dist/shell-NZABRJLA.js +16 -0
  42. package/dist/shell-NZABRJLA.js.map +1 -0
  43. package/dist/skill-installer-F67OAOQN.js +121 -0
  44. package/dist/skill-installer-F67OAOQN.js.map +1 -0
  45. package/dist/{skill-usage-detector-EO26MRYV.js → skill-usage-detector-MSW5VWQZ.js} +2 -2
  46. package/dist/skill-usage-detector-MSW5VWQZ.js.map +1 -0
  47. package/dist/tray-WKFGUUTO.js +346 -0
  48. package/dist/tray-WKFGUUTO.js.map +1 -0
  49. package/package.json +62 -63
  50. package/scripts/postinstall.mjs +415 -364
  51. package/scripts/tray-helper-darwin +0 -0
  52. package/scripts/tray-helper-darwin.swift +180 -180
  53. package/scripts/tray-helper-linux.py +322 -0
  54. package/scripts/tray-helper-windows.cs +322 -0
  55. package/dist/api-client-KUQW7FSC.js +0 -12
  56. package/dist/chunk-2CVEPT6U.js.map +0 -1
  57. package/dist/chunk-CPL3P2OF.js.map +0 -1
  58. package/dist/chunk-ODOZM4QV.js.map +0 -1
  59. package/dist/chunk-WJKZWKER.js.map +0 -1
  60. package/dist/claude-watcher-N6GN6WHJ.js.map +0 -1
  61. package/dist/database-F3BFFZKG.js +0 -9
  62. package/dist/skill-usage-detector-EO26MRYV.js.map +0 -1
  63. package/dist/tray-UCAI2U2C.js +0 -408
  64. package/dist/tray-UCAI2U2C.js.map +0 -1
  65. /package/dist/{api-client-KUQW7FSC.js.map → api-client-BF6GDR7Q.js.map} +0 -0
  66. /package/dist/{config-P5EM5L7N.js.map → config-ZOKAP2LJ.js.map} +0 -0
  67. /package/dist/{database-F3BFFZKG.js.map → daemon-6DTCMOJB.js.map} +0 -0
  68. /package/dist/{paths-INOKEM66.js.map → database-KQY5OSCS.js.map} +0 -0
package/README.md CHANGED
@@ -1,198 +1,198 @@
1
- # Skillo CLI
2
-
3
- Autonomous workflow learning & skill generation system.
4
-
5
- **Learn workflows by observation, not explanation.**
6
-
7
- **Website:** [skillo.one](https://skillo.one)
8
-
9
- ## Installation
10
-
11
- ```bash
12
- # Install globally
13
- npm install -g skillo
14
-
15
- # Or use with npx
16
- npx skillo --help
17
- ```
18
-
19
- ## Quick Start
20
-
21
- ```bash
22
- # Login to skillo.one (opens browser for OAuth)
23
- skillo login
24
-
25
- # Enable tracking for your project (privacy-first: opt-in only)
26
- cd /path/to/your/project
27
- skillo track
28
-
29
- # Sync Claude Code history
30
- skillo claude sync
31
-
32
- # Check tracking status
33
- skillo project status
34
- ```
35
-
36
- ## Commands
37
-
38
- ### Authentication
39
-
40
- ```bash
41
- # Login to skillo.one (opens browser)
42
- skillo login
43
-
44
- # Check login status
45
- skillo whoami
46
-
47
- # Logout
48
- skillo logout
49
- ```
50
-
51
- ### Project Tracking (Privacy-First)
52
-
53
- ```bash
54
- # Enable tracking for current project
55
- skillo track
56
-
57
- # Disable tracking
58
- skillo untrack
59
-
60
- # Check tracking status
61
- skillo project status
62
-
63
- # List all tracked projects
64
- skillo project list
65
- ```
66
-
67
- ### Claude Code Sync
68
-
69
- ```bash
70
- # Sync Claude Code conversation history
71
- skillo claude sync
72
-
73
- # Sync specific project only
74
- skillo claude sync --project /path/to/project
75
- ```
76
-
77
- ### Sync
78
-
79
- ```bash
80
- # Pull skills and patterns from platform
81
- skillo sync --pull
82
-
83
- # Push local patterns to platform
84
- skillo sync --push
85
-
86
- # Sync everything
87
- skillo sync --push --pull
88
- ```
89
-
90
- ### Patterns
91
-
92
- ```bash
93
- # List detected patterns
94
- skillo patterns list
95
-
96
- # Show pattern details
97
- skillo patterns show <id>
98
-
99
- # Generate a skill from a pattern
100
- skillo patterns generate <id>
101
- ```
102
-
103
- ### Skills
104
-
105
- ```bash
106
- # List generated skills
107
- skillo skills list
108
-
109
- # Show skill details
110
- skillo skills show <name>
111
-
112
- # Open skills directory
113
- skillo skills open
114
- ```
115
-
116
- ### Status
117
-
118
- ```bash
119
- # Check overall status
120
- skillo status
121
- ```
122
-
123
- ## Configuration
124
-
125
- Configuration is stored in `~/.config/skillo/config.yaml`.
126
-
127
- Key settings:
128
-
129
- ```yaml
130
- # Pattern detection
131
- pattern_detection:
132
- min_count: 3 # Occurrences before detection
133
- session_timeout: 30 # Minutes of inactivity
134
-
135
- # Privacy
136
- privacy:
137
- auto_redact: true # Redact sensitive data
138
- track_output: false # Don't track command output
139
-
140
- # Notifications
141
- notifications:
142
- enabled: true
143
- style: inline # inline, desktop, or both
144
-
145
- # Skill generation
146
- skill_generation:
147
- include_scripts: true
148
- include_examples: true
149
- ```
150
-
151
- ## How It Works
152
-
153
- 1. **Login**: Run `skillo login` to authenticate with [skillo.one](https://skillo.one). Opens your browser for secure OAuth.
154
-
155
- 2. **Track Projects**: Run `skillo track` in any project directory to enable tracking. Nothing is tracked by default (privacy-first).
156
-
157
- 3. **Pattern Detection**: Skillo analyzes your Claude Code conversations to identify repeated workflows and patterns.
158
-
159
- 4. **Skill Generation**: Convert detected patterns into reusable AI skills through the dashboard at [skillo.one](https://skillo.one).
160
-
161
- 5. **Team Sharing**: Skills are automatically matched to team members via git remote detection—no GitHub OAuth required.
162
-
163
- ## Directory Structure
164
-
165
- ```
166
- ~/.config/skillo/ # Config directory
167
- └── config.yaml # Configuration + API key
168
-
169
- ~/.claude/skills/ # Skills directory (Claude Code)
170
- ├── my-workflow/
171
- │ ├── SKILL.md
172
- │ └── scripts/
173
- └── another-skill/
174
- └── SKILL.md
175
- ```
176
-
177
- ## Privacy
178
-
179
- Skillo is built with privacy as a core principle:
180
-
181
- - **Explicit Opt-In** — Run `skillo track` to enable tracking per project
182
- - **Local Reading** — Claude Code history is read locally, never scraped
183
- - **No GitHub OAuth** — Git remote detection works locally
184
- - **Secure Sync** — All data encrypted in transit
185
-
186
- ## Requirements
187
-
188
- - Node.js 18+
189
- - npm or yarn
190
- - Claude Code (for conversation sync)
191
-
192
- ## Support
193
-
194
- - **Website:** [skillo.one](https://skillo.one)
195
-
196
- ## License
197
-
198
- Proprietary - All rights reserved.
1
+ # Skillo CLI
2
+
3
+ Autonomous workflow learning & skill generation system.
4
+
5
+ **Learn workflows by observation, not explanation.**
6
+
7
+ **Website:** [skillo.one](https://skillo.one)
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ # Install globally
13
+ npm install -g skillo
14
+
15
+ # Or use with npx
16
+ npx skillo --help
17
+ ```
18
+
19
+ ## Quick Start
20
+
21
+ ```bash
22
+ # Login to skillo.one (opens browser for OAuth)
23
+ skillo login
24
+
25
+ # Enable tracking for your project (privacy-first: opt-in only)
26
+ cd /path/to/your/project
27
+ skillo track
28
+
29
+ # Sync Claude Code history
30
+ skillo claude sync
31
+
32
+ # Check tracking status
33
+ skillo project status
34
+ ```
35
+
36
+ ## Commands
37
+
38
+ ### Authentication
39
+
40
+ ```bash
41
+ # Login to skillo.one (opens browser)
42
+ skillo login
43
+
44
+ # Check login status
45
+ skillo whoami
46
+
47
+ # Logout
48
+ skillo logout
49
+ ```
50
+
51
+ ### Project Tracking (Privacy-First)
52
+
53
+ ```bash
54
+ # Enable tracking for current project
55
+ skillo track
56
+
57
+ # Disable tracking
58
+ skillo untrack
59
+
60
+ # Check tracking status
61
+ skillo project status
62
+
63
+ # List all tracked projects
64
+ skillo project list
65
+ ```
66
+
67
+ ### Claude Code Sync
68
+
69
+ ```bash
70
+ # Sync Claude Code conversation history
71
+ skillo claude sync
72
+
73
+ # Sync specific project only
74
+ skillo claude sync --project /path/to/project
75
+ ```
76
+
77
+ ### Sync
78
+
79
+ ```bash
80
+ # Pull skills and patterns from platform
81
+ skillo sync --pull
82
+
83
+ # Push local patterns to platform
84
+ skillo sync --push
85
+
86
+ # Sync everything
87
+ skillo sync --push --pull
88
+ ```
89
+
90
+ ### Patterns
91
+
92
+ ```bash
93
+ # List detected patterns
94
+ skillo patterns list
95
+
96
+ # Show pattern details
97
+ skillo patterns show <id>
98
+
99
+ # Generate a skill from a pattern
100
+ skillo patterns generate <id>
101
+ ```
102
+
103
+ ### Skills
104
+
105
+ ```bash
106
+ # List generated skills
107
+ skillo skills list
108
+
109
+ # Show skill details
110
+ skillo skills show <name>
111
+
112
+ # Open skills directory
113
+ skillo skills open
114
+ ```
115
+
116
+ ### Status
117
+
118
+ ```bash
119
+ # Check overall status
120
+ skillo status
121
+ ```
122
+
123
+ ## Configuration
124
+
125
+ Configuration is stored in `~/.config/skillo/config.yaml`.
126
+
127
+ Key settings:
128
+
129
+ ```yaml
130
+ # Pattern detection
131
+ pattern_detection:
132
+ min_count: 3 # Occurrences before detection
133
+ session_timeout: 30 # Minutes of inactivity
134
+
135
+ # Privacy
136
+ privacy:
137
+ auto_redact: true # Redact sensitive data
138
+ track_output: false # Don't track command output
139
+
140
+ # Notifications
141
+ notifications:
142
+ enabled: true
143
+ style: inline # inline, desktop, or both
144
+
145
+ # Skill generation
146
+ skill_generation:
147
+ include_scripts: true
148
+ include_examples: true
149
+ ```
150
+
151
+ ## How It Works
152
+
153
+ 1. **Login**: Run `skillo login` to authenticate with [skillo.one](https://skillo.one). Opens your browser for secure OAuth.
154
+
155
+ 2. **Track Projects**: Run `skillo track` in any project directory to enable tracking. Nothing is tracked by default (privacy-first).
156
+
157
+ 3. **Pattern Detection**: Skillo analyzes your Claude Code conversations to identify repeated workflows and patterns.
158
+
159
+ 4. **Skill Generation**: Convert detected patterns into reusable AI skills through the dashboard at [skillo.one](https://skillo.one).
160
+
161
+ 5. **Team Sharing**: Skills are automatically matched to team members via git remote detection—no GitHub OAuth required.
162
+
163
+ ## Directory Structure
164
+
165
+ ```
166
+ ~/.config/skillo/ # Config directory
167
+ └── config.yaml # Configuration + API key
168
+
169
+ ~/.claude/skills/ # Skills directory (Claude Code)
170
+ ├── my-workflow/
171
+ │ ├── SKILL.md
172
+ │ └── scripts/
173
+ └── another-skill/
174
+ └── SKILL.md
175
+ ```
176
+
177
+ ## Privacy
178
+
179
+ Skillo is built with privacy as a core principle:
180
+
181
+ - **Explicit Opt-In** — Run `skillo track` to enable tracking per project
182
+ - **Local Reading** — Claude Code history is read locally, never scraped
183
+ - **No GitHub OAuth** — Git remote detection works locally
184
+ - **Secure Sync** — All data encrypted in transit
185
+
186
+ ## Requirements
187
+
188
+ - Node.js 18+
189
+ - npm or yarn
190
+ - Claude Code (for conversation sync)
191
+
192
+ ## Support
193
+
194
+ - **Website:** [skillo.one](https://skillo.one)
195
+
196
+ ## License
197
+
198
+ Proprietary - All rights reserved.
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ ApiClient,
4
+ getApiClient
5
+ } from "./chunk-RQ2SC5HW.js";
6
+ import "./chunk-QUXHHRRK.js";
7
+ import "./chunk-63FVALWX.js";
8
+ export {
9
+ ApiClient,
10
+ getApiClient
11
+ };
12
+ //# sourceMappingURL=api-client-BF6GDR7Q.js.map
@@ -82,4 +82,4 @@ export {
82
82
  getActiveSessionsDir,
83
83
  getShellIntegrationDir
84
84
  };
85
- //# sourceMappingURL=chunk-WJKZWKER.js.map
85
+ //# sourceMappingURL=chunk-63FVALWX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/paths.ts"],"sourcesContent":["/**\r\n * Path utilities for Skillo.\r\n *\r\n * Handles platform-specific path resolution for data directories,\r\n * configuration files, and skill storage locations.\r\n */\r\n\r\nimport { homedir } from \"os\";\r\nimport { join } from \"path\";\r\nimport { mkdirSync, existsSync } from \"fs\";\r\n\r\nexport function getHomeDir(): string {\r\n return homedir();\r\n}\r\n\r\n/**\r\n * Get Skillo data directory.\r\n * This is where the database and other data files are stored.\r\n *\r\n * - Linux/macOS: ~/.skillo/\r\n * - Windows: %USERPROFILE%/.skillo/\r\n */\r\nexport function getDataDir(): string {\r\n const envPath = process.env.SKILLO_DATA_DIR;\r\n if (envPath) return envPath;\r\n\r\n return join(getHomeDir(), \".skillo\");\r\n}\r\n\r\n/**\r\n * Get Skillo configuration directory.\r\n * This is where config.yaml and other configuration files are stored.\r\n *\r\n * - Linux: ~/.config/skillo/\r\n * - macOS: ~/.config/skillo/\r\n * - Windows: %USERPROFILE%/.config/skillo/\r\n */\r\nexport function getConfigDir(): string {\r\n const envPath = process.env.SKILLO_CONFIG_DIR;\r\n if (envPath) return envPath;\r\n\r\n const xdgConfig = process.env.XDG_CONFIG_HOME;\r\n if (xdgConfig) return join(xdgConfig, \"skillo\");\r\n\r\n return join(getHomeDir(), \".config\", \"skillo\");\r\n}\r\n\r\n/**\r\n * Get personal skills directory.\r\n * This is where generated skills are stored and where Claude Code\r\n * reads personal skills from.\r\n *\r\n * - All platforms: ~/.claude/skills/\r\n */\r\nexport function getSkillsDir(): string {\r\n const envPath = process.env.SKILLO_SKILLS_DIR;\r\n if (envPath) return envPath;\r\n\r\n return join(getClaudeDir(), \"skills\");\r\n}\r\n\r\n/**\r\n * Get Claude Code directory.\r\n * This is where Claude Code stores its data, including conversations.\r\n *\r\n * - All platforms: ~/.claude/\r\n */\r\nexport function getClaudeDir(): string {\r\n return join(getHomeDir(), \".claude\");\r\n}\r\n\r\n/**\r\n * Get project-specific skills directory.\r\n * This is where project-specific skills are stored.\r\n *\r\n * - Path: <project>/.claude/skills/\r\n */\r\nexport function getProjectSkillsDir(projectPath?: string): string {\r\n const project = projectPath || process.cwd();\r\n return join(project, \".claude\", \"skills\");\r\n}\r\n\r\n/**\r\n * Get team skills directory.\r\n * This is where team skills are synced to.\r\n *\r\n * - Path: ~/.claude/skills/team/<team-slug>/\r\n */\r\nexport function getTeamSkillsDir(teamSlug?: string): string {\r\n const base = join(getSkillsDir(), \"team\");\r\n if (teamSlug) return join(base, teamSlug);\r\n return base;\r\n}\r\n\r\n/**\r\n * Ensure a directory exists, creating it if necessary.\r\n *\r\n * @returns True if directory was created, False if it already existed.\r\n */\r\nexport function ensureDirectory(path: string): boolean {\r\n if (existsSync(path)) {\r\n return false;\r\n }\r\n\r\n mkdirSync(path, { recursive: true });\r\n return true;\r\n}\r\n\r\n/**\r\n * Get path to daemon log file.\r\n */\r\nexport function getLogFile(): string {\r\n return join(getDataDir(), \"daemon.log\");\r\n}\r\n\r\n/**\r\n * Get path to daemon PID file.\r\n */\r\nexport function getPidFile(): string {\r\n return join(getDataDir(), \"daemon.pid\");\r\n}\r\n\r\n/**\r\n * Get path to SQLite database file.\r\n */\r\nexport function getDbPath(): string {\r\n return join(getDataDir(), \"skillo.db\");\r\n}\r\n\r\n/**\r\n * Get path to config file.\r\n */\r\nexport function getConfigFile(): string {\r\n return join(getConfigDir(), \"config.yaml\");\r\n}\r\n\r\n/**\r\n * Get path to tracked projects cache file.\r\n * Written by daemon, read by shell hooks for fast project detection.\r\n */\r\nexport function getTrackedProjectsCacheFile(): string {\r\n return join(getDataDir(), \"tracked-projects.json\");\r\n}\r\n\r\n/**\r\n * Get path to active sessions directory.\r\n * Each terminal gets a file named by its PID.\r\n */\r\nexport function getActiveSessionsDir(): string {\r\n return join(getDataDir(), \"active-sessions\");\r\n}\r\n\r\n/**\r\n * Get path to shell integration directory.\r\n */\r\nexport function getShellIntegrationDir(): string {\r\n return join(getDataDir(), \"shell-integration\");\r\n}\r\n"],"mappings":";;;AAOA,SAAS,eAAe;AACxB,SAAS,YAAY;AACrB,SAAS,WAAW,kBAAkB;AAE/B,SAAS,aAAqB;AACnC,SAAO,QAAQ;AACjB;AASO,SAAS,aAAqB;AACnC,QAAM,UAAU,QAAQ,IAAI;AAC5B,MAAI,QAAS,QAAO;AAEpB,SAAO,KAAK,WAAW,GAAG,SAAS;AACrC;AAUO,SAAS,eAAuB;AACrC,QAAM,UAAU,QAAQ,IAAI;AAC5B,MAAI,QAAS,QAAO;AAEpB,QAAM,YAAY,QAAQ,IAAI;AAC9B,MAAI,UAAW,QAAO,KAAK,WAAW,QAAQ;AAE9C,SAAO,KAAK,WAAW,GAAG,WAAW,QAAQ;AAC/C;AASO,SAAS,eAAuB;AACrC,QAAM,UAAU,QAAQ,IAAI;AAC5B,MAAI,QAAS,QAAO;AAEpB,SAAO,KAAK,aAAa,GAAG,QAAQ;AACtC;AAQO,SAAS,eAAuB;AACrC,SAAO,KAAK,WAAW,GAAG,SAAS;AACrC;AAQO,SAAS,oBAAoB,aAA8B;AAChE,QAAM,UAAU,eAAe,QAAQ,IAAI;AAC3C,SAAO,KAAK,SAAS,WAAW,QAAQ;AAC1C;AAQO,SAAS,iBAAiB,UAA2B;AAC1D,QAAM,OAAO,KAAK,aAAa,GAAG,MAAM;AACxC,MAAI,SAAU,QAAO,KAAK,MAAM,QAAQ;AACxC,SAAO;AACT;AAOO,SAAS,gBAAgB,MAAuB;AACrD,MAAI,WAAW,IAAI,GAAG;AACpB,WAAO;AAAA,EACT;AAEA,YAAU,MAAM,EAAE,WAAW,KAAK,CAAC;AACnC,SAAO;AACT;AAKO,SAAS,aAAqB;AACnC,SAAO,KAAK,WAAW,GAAG,YAAY;AACxC;AAKO,SAAS,aAAqB;AACnC,SAAO,KAAK,WAAW,GAAG,YAAY;AACxC;AAKO,SAAS,YAAoB;AAClC,SAAO,KAAK,WAAW,GAAG,WAAW;AACvC;AAKO,SAAS,gBAAwB;AACtC,SAAO,KAAK,aAAa,GAAG,aAAa;AAC3C;AAMO,SAAS,8BAAsC;AACpD,SAAO,KAAK,WAAW,GAAG,uBAAuB;AACnD;AAMO,SAAS,uBAA+B;AAC7C,SAAO,KAAK,WAAW,GAAG,iBAAiB;AAC7C;AAKO,SAAS,yBAAiC;AAC/C,SAAO,KAAK,WAAW,GAAG,mBAAmB;AAC/C;","names":[]}
@@ -0,0 +1,113 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/utils/git.ts
4
+ import { execSync } from "child_process";
5
+ import { existsSync } from "fs";
6
+ import { join, dirname, basename } from "path";
7
+ function getGitInfo(projectPath) {
8
+ const result = {
9
+ isGitRepo: false,
10
+ rootPath: null,
11
+ remote: null,
12
+ remoteNormalized: null,
13
+ branch: null,
14
+ projectName: null
15
+ };
16
+ try {
17
+ const rootPath = execSync("git rev-parse --show-toplevel", {
18
+ cwd: projectPath,
19
+ encoding: "utf-8",
20
+ stdio: ["pipe", "pipe", "pipe"]
21
+ }).trim();
22
+ if (!rootPath) return result;
23
+ result.isGitRepo = true;
24
+ result.rootPath = rootPath;
25
+ result.projectName = basename(rootPath);
26
+ try {
27
+ result.branch = execSync("git rev-parse --abbrev-ref HEAD", {
28
+ cwd: projectPath,
29
+ encoding: "utf-8",
30
+ stdio: ["pipe", "pipe", "pipe"]
31
+ }).trim();
32
+ } catch {
33
+ }
34
+ try {
35
+ result.remote = execSync("git remote get-url origin", {
36
+ cwd: projectPath,
37
+ encoding: "utf-8",
38
+ stdio: ["pipe", "pipe", "pipe"]
39
+ }).trim();
40
+ } catch {
41
+ try {
42
+ const remotes = execSync("git remote", {
43
+ cwd: projectPath,
44
+ encoding: "utf-8",
45
+ stdio: ["pipe", "pipe", "pipe"]
46
+ }).trim().split("\n");
47
+ if (remotes.length > 0 && remotes[0]) {
48
+ result.remote = execSync(`git remote get-url ${remotes[0]}`, {
49
+ cwd: projectPath,
50
+ encoding: "utf-8",
51
+ stdio: ["pipe", "pipe", "pipe"]
52
+ }).trim();
53
+ }
54
+ } catch {
55
+ }
56
+ }
57
+ if (result.remote) {
58
+ result.remoteNormalized = normalizeGitRemote(result.remote);
59
+ }
60
+ } catch {
61
+ }
62
+ return result;
63
+ }
64
+ function normalizeGitRemote(remoteUrl) {
65
+ let url = remoteUrl.trim();
66
+ url = url.replace(/\.git$/, "");
67
+ const sshMatch = url.match(/^git@([^:]+):(.+)$/);
68
+ if (sshMatch) {
69
+ return `${sshMatch[1]}/${sshMatch[2]}`;
70
+ }
71
+ try {
72
+ let normalized = url.replace(/^(https?|git|ssh):\/\//, "").replace(/^git@/, "");
73
+ normalized = normalized.replace(/^[^@]+@/, "");
74
+ normalized = normalized.replace(/:\d+\//, "/");
75
+ normalized = normalized.replace(/\/+/g, "/");
76
+ normalized = normalized.replace(/^\/|\/$/g, "");
77
+ return normalized.toLowerCase();
78
+ } catch {
79
+ return url.toLowerCase();
80
+ }
81
+ }
82
+ function findGitRoot(startPath) {
83
+ let current = startPath;
84
+ while (current !== dirname(current)) {
85
+ if (existsSync(join(current, ".git"))) {
86
+ return current;
87
+ }
88
+ current = dirname(current);
89
+ }
90
+ return null;
91
+ }
92
+ function isInsideGitRepo(path) {
93
+ return findGitRoot(path) !== null;
94
+ }
95
+ function parseGitRemote(normalizedRemote) {
96
+ const parts = normalizedRemote.split("/");
97
+ if (parts.length < 3) return null;
98
+ return {
99
+ host: parts[0],
100
+ owner: parts[1],
101
+ repo: parts.slice(2).join("/")
102
+ // Handle nested paths like gitlab subgroups
103
+ };
104
+ }
105
+
106
+ export {
107
+ getGitInfo,
108
+ normalizeGitRemote,
109
+ findGitRoot,
110
+ isInsideGitRepo,
111
+ parseGitRemote
112
+ };
113
+ //# sourceMappingURL=chunk-6GOJPFZ7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/git.ts"],"sourcesContent":["/**\r\n * Git utilities for project detection and identification.\r\n */\r\n\r\nimport { execSync } from \"child_process\";\r\nimport { existsSync } from \"fs\";\r\nimport { join, dirname, basename } from \"path\";\r\n\r\nexport interface GitInfo {\r\n isGitRepo: boolean;\r\n rootPath: string | null;\r\n remote: string | null;\r\n remoteNormalized: string | null;\r\n branch: string | null;\r\n projectName: string | null;\r\n}\r\n\r\n/**\r\n * Get git information for a given path.\r\n */\r\nexport function getGitInfo(projectPath: string): GitInfo {\r\n const result: GitInfo = {\r\n isGitRepo: false,\r\n rootPath: null,\r\n remote: null,\r\n remoteNormalized: null,\r\n branch: null,\r\n projectName: null,\r\n };\r\n\r\n try {\r\n // Check if it's a git repo and get root\r\n const rootPath = execSync(\"git rev-parse --show-toplevel\", {\r\n cwd: projectPath,\r\n encoding: \"utf-8\",\r\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\r\n }).trim();\r\n\r\n if (!rootPath) return result;\r\n\r\n result.isGitRepo = true;\r\n result.rootPath = rootPath;\r\n result.projectName = basename(rootPath);\r\n\r\n // Get current branch\r\n try {\r\n result.branch = execSync(\"git rev-parse --abbrev-ref HEAD\", {\r\n cwd: projectPath,\r\n encoding: \"utf-8\",\r\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\r\n }).trim();\r\n } catch {\r\n // Might be in detached HEAD state\r\n }\r\n\r\n // Get remote URL (prefer origin)\r\n try {\r\n result.remote = execSync(\"git remote get-url origin\", {\r\n cwd: projectPath,\r\n encoding: \"utf-8\",\r\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\r\n }).trim();\r\n } catch {\r\n // Try to get any remote\r\n try {\r\n const remotes = execSync(\"git remote\", {\r\n cwd: projectPath,\r\n encoding: \"utf-8\",\r\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\r\n }).trim().split(\"\\n\");\r\n\r\n if (remotes.length > 0 && remotes[0]) {\r\n result.remote = execSync(`git remote get-url ${remotes[0]}`, {\r\n cwd: projectPath,\r\n encoding: \"utf-8\",\r\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\r\n }).trim();\r\n }\r\n } catch {\r\n // No remotes configured\r\n }\r\n }\r\n\r\n // Normalize the remote URL for team matching\r\n if (result.remote) {\r\n result.remoteNormalized = normalizeGitRemote(result.remote);\r\n }\r\n } catch {\r\n // Not a git repository\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Normalize a git remote URL for consistent matching across team members.\r\n * Converts various formats to: \"host/owner/repo\"\r\n *\r\n * Examples:\r\n * - git@github.com:acme/webapp.git -> github.com/acme/webapp\r\n * - https://github.com/acme/webapp.git -> github.com/acme/webapp\r\n * - ssh://git@github.com/acme/webapp -> github.com/acme/webapp\r\n * - git://github.com/acme/webapp.git -> github.com/acme/webapp\r\n */\r\nexport function normalizeGitRemote(remoteUrl: string): string {\r\n let url = remoteUrl.trim();\r\n\r\n // Remove .git suffix\r\n url = url.replace(/\\.git$/, \"\");\r\n\r\n // Handle SSH format: git@github.com:owner/repo\r\n const sshMatch = url.match(/^git@([^:]+):(.+)$/);\r\n if (sshMatch) {\r\n return `${sshMatch[1]}/${sshMatch[2]}`;\r\n }\r\n\r\n // Handle various URL formats\r\n try {\r\n // Remove protocol prefix for parsing\r\n let normalized = url\r\n .replace(/^(https?|git|ssh):\\/\\//, \"\")\r\n .replace(/^git@/, \"\");\r\n\r\n // Remove username if present (e.g., git@host or user@host)\r\n normalized = normalized.replace(/^[^@]+@/, \"\");\r\n\r\n // Remove port if present\r\n normalized = normalized.replace(/:\\d+\\//, \"/\");\r\n\r\n // Clean up any double slashes\r\n normalized = normalized.replace(/\\/+/g, \"/\");\r\n\r\n // Remove leading/trailing slashes\r\n normalized = normalized.replace(/^\\/|\\/$/g, \"\");\r\n\r\n return normalized.toLowerCase();\r\n } catch {\r\n // Fallback: return as-is but lowercase\r\n return url.toLowerCase();\r\n }\r\n}\r\n\r\n/**\r\n * Find git root by walking up the directory tree.\r\n */\r\nexport function findGitRoot(startPath: string): string | null {\r\n let current = startPath;\r\n\r\n while (current !== dirname(current)) {\r\n if (existsSync(join(current, \".git\"))) {\r\n return current;\r\n }\r\n current = dirname(current);\r\n }\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * Check if a path is inside a git repository.\r\n */\r\nexport function isInsideGitRepo(path: string): boolean {\r\n return findGitRoot(path) !== null;\r\n}\r\n\r\n/**\r\n * Extract owner and repo name from a normalized git remote.\r\n */\r\nexport function parseGitRemote(normalizedRemote: string): { host: string; owner: string; repo: string } | null {\r\n const parts = normalizedRemote.split(\"/\");\r\n\r\n if (parts.length < 3) return null;\r\n\r\n return {\r\n host: parts[0],\r\n owner: parts[1],\r\n repo: parts.slice(2).join(\"/\"), // Handle nested paths like gitlab subgroups\r\n };\r\n}\r\n"],"mappings":"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","names":[]}
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ ensureDirectory,
4
+ getDataDir
5
+ } from "./chunk-63FVALWX.js";
6
+
7
+ // src/utils/status-writer.ts
8
+ import { writeFileSync, readFileSync, existsSync } from "fs";
9
+ import { join } from "path";
10
+ var STATUS_FILE = "daemon-status.json";
11
+ var WRITE_INTERVAL_MS = 1e4;
12
+ var StatusWriter = class _StatusWriter {
13
+ intervalId = null;
14
+ status;
15
+ filePath;
16
+ constructor() {
17
+ this.filePath = join(getDataDir(), STATUS_FILE);
18
+ this.status = {
19
+ running: true,
20
+ pid: process.pid,
21
+ startedAt: (/* @__PURE__ */ new Date()).toISOString(),
22
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
23
+ claudeWatcher: { lastSync: null, promptsSynced: 0, lastError: null },
24
+ skillDetector: { deployedSkills: 0, usagesDetected: 0, lastDetection: null, lastError: null },
25
+ trackedProjects: [],
26
+ activeSessions: 0
27
+ };
28
+ }
29
+ /** Start periodic writes */
30
+ start() {
31
+ ensureDirectory(getDataDir());
32
+ this.write();
33
+ this.intervalId = setInterval(() => this.write(), WRITE_INTERVAL_MS);
34
+ }
35
+ /** Stop writing and mark as not running */
36
+ stop() {
37
+ if (this.intervalId) {
38
+ clearInterval(this.intervalId);
39
+ this.intervalId = null;
40
+ }
41
+ this.status.running = false;
42
+ this.status.pid = null;
43
+ this.status.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
44
+ this.write();
45
+ }
46
+ /** Merge partial status updates */
47
+ update(partial) {
48
+ if (partial.claudeWatcher) {
49
+ this.status.claudeWatcher = { ...this.status.claudeWatcher, ...partial.claudeWatcher };
50
+ delete partial.claudeWatcher;
51
+ }
52
+ if (partial.skillDetector) {
53
+ this.status.skillDetector = { ...this.status.skillDetector, ...partial.skillDetector };
54
+ delete partial.skillDetector;
55
+ }
56
+ if (partial.skillInstaller) {
57
+ this.status.skillInstaller = { ...this.status.skillInstaller, ...partial.skillInstaller };
58
+ delete partial.skillInstaller;
59
+ }
60
+ Object.assign(this.status, partial);
61
+ }
62
+ /** Get the status file path */
63
+ static getStatusFilePath() {
64
+ return join(getDataDir(), STATUS_FILE);
65
+ }
66
+ /** Read current status from disk (static, for tray/status commands) */
67
+ static read() {
68
+ const filePath = _StatusWriter.getStatusFilePath();
69
+ try {
70
+ if (existsSync(filePath)) {
71
+ return JSON.parse(readFileSync(filePath, "utf-8"));
72
+ }
73
+ } catch {
74
+ }
75
+ return null;
76
+ }
77
+ write() {
78
+ this.status.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
79
+ try {
80
+ writeFileSync(this.filePath, JSON.stringify(this.status, null, 2), "utf-8");
81
+ } catch {
82
+ }
83
+ }
84
+ };
85
+
86
+ export {
87
+ StatusWriter
88
+ };
89
+ //# sourceMappingURL=chunk-6UGTWBUW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/status-writer.ts"],"sourcesContent":["/**\r\n * StatusWriter — writes daemon status JSON for tray icon and diagnostics.\r\n *\r\n * Writes ~/.skillo/daemon-status.json every 10s and on key events.\r\n * Tray icon and `skillo status` read this file.\r\n */\r\n\r\nimport { writeFileSync, readFileSync, existsSync } from \"fs\";\r\nimport { join } from \"path\";\r\nimport { getDataDir, ensureDirectory } from \"./paths.js\";\r\n\r\nexport interface DaemonStatus {\r\n running: boolean;\r\n pid: number | null;\r\n startedAt: string | null;\r\n updatedAt: string;\r\n user?: string;\r\n claudeWatcher?: {\r\n lastSync?: string | null;\r\n promptsSynced?: number;\r\n lastError?: string | null;\r\n };\r\n skillDetector?: {\r\n deployedSkills?: number;\r\n usagesDetected?: number;\r\n lastDetection?: string | null;\r\n lastError?: string | null;\r\n };\r\n skillInstaller?: {\r\n lastInstall?: string | null;\r\n lastUninstall?: string | null;\r\n lastAction?: string | null;\r\n lastError?: string | null;\r\n };\r\n trackedProjects?: Array<{ name: string; path: string }>;\r\n activeSessions?: number;\r\n}\r\n\r\nconst STATUS_FILE = \"daemon-status.json\";\r\nconst WRITE_INTERVAL_MS = 10000;\r\n\r\nexport class StatusWriter {\r\n private intervalId: ReturnType<typeof setInterval> | null = null;\r\n private status: DaemonStatus;\r\n private filePath: string;\r\n\r\n constructor() {\r\n this.filePath = join(getDataDir(), STATUS_FILE);\r\n this.status = {\r\n running: true,\r\n pid: process.pid,\r\n startedAt: new Date().toISOString(),\r\n updatedAt: new Date().toISOString(),\r\n claudeWatcher: { lastSync: null, promptsSynced: 0, lastError: null },\r\n skillDetector: { deployedSkills: 0, usagesDetected: 0, lastDetection: null, lastError: null },\r\n trackedProjects: [],\r\n activeSessions: 0,\r\n };\r\n }\r\n\r\n /** Start periodic writes */\r\n start() {\r\n ensureDirectory(getDataDir());\r\n this.write();\r\n this.intervalId = setInterval(() => this.write(), WRITE_INTERVAL_MS);\r\n }\r\n\r\n /** Stop writing and mark as not running */\r\n stop() {\r\n if (this.intervalId) {\r\n clearInterval(this.intervalId);\r\n this.intervalId = null;\r\n }\r\n this.status.running = false;\r\n this.status.pid = null;\r\n this.status.updatedAt = new Date().toISOString();\r\n this.write();\r\n }\r\n\r\n /** Merge partial status updates */\r\n update(partial: Partial<DaemonStatus>) {\r\n // Deep merge for nested objects\r\n if (partial.claudeWatcher) {\r\n this.status.claudeWatcher = { ...this.status.claudeWatcher, ...partial.claudeWatcher };\r\n delete partial.claudeWatcher;\r\n }\r\n if (partial.skillDetector) {\r\n this.status.skillDetector = { ...this.status.skillDetector, ...partial.skillDetector };\r\n delete partial.skillDetector;\r\n }\r\n if (partial.skillInstaller) {\r\n this.status.skillInstaller = { ...this.status.skillInstaller, ...partial.skillInstaller };\r\n delete partial.skillInstaller;\r\n }\r\n Object.assign(this.status, partial);\r\n }\r\n\r\n /** Get the status file path */\r\n static getStatusFilePath(): string {\r\n return join(getDataDir(), STATUS_FILE);\r\n }\r\n\r\n /** Read current status from disk (static, for tray/status commands) */\r\n static read(): DaemonStatus | null {\r\n const filePath = StatusWriter.getStatusFilePath();\r\n try {\r\n if (existsSync(filePath)) {\r\n return JSON.parse(readFileSync(filePath, \"utf-8\"));\r\n }\r\n } catch {\r\n // ignore\r\n }\r\n return null;\r\n }\r\n\r\n private write() {\r\n this.status.updatedAt = new Date().toISOString();\r\n try {\r\n writeFileSync(this.filePath, JSON.stringify(this.status, null, 2), \"utf-8\");\r\n } catch {\r\n // Can't write status, ignore\r\n }\r\n }\r\n}\r\n"],"mappings":";;;;;;;AAOA,SAAS,eAAe,cAAc,kBAAkB;AACxD,SAAS,YAAY;AA8BrB,IAAM,cAAc;AACpB,IAAM,oBAAoB;AAEnB,IAAM,eAAN,MAAM,cAAa;AAAA,EAChB,aAAoD;AAAA,EACpD;AAAA,EACA;AAAA,EAER,cAAc;AACZ,SAAK,WAAW,KAAK,WAAW,GAAG,WAAW;AAC9C,SAAK,SAAS;AAAA,MACZ,SAAS;AAAA,MACT,KAAK,QAAQ;AAAA,MACb,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MAClC,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MAClC,eAAe,EAAE,UAAU,MAAM,eAAe,GAAG,WAAW,KAAK;AAAA,MACnE,eAAe,EAAE,gBAAgB,GAAG,gBAAgB,GAAG,eAAe,MAAM,WAAW,KAAK;AAAA,MAC5F,iBAAiB,CAAC;AAAA,MAClB,gBAAgB;AAAA,IAClB;AAAA,EACF;AAAA;AAAA,EAGA,QAAQ;AACN,oBAAgB,WAAW,CAAC;AAC5B,SAAK,MAAM;AACX,SAAK,aAAa,YAAY,MAAM,KAAK,MAAM,GAAG,iBAAiB;AAAA,EACrE;AAAA;AAAA,EAGA,OAAO;AACL,QAAI,KAAK,YAAY;AACnB,oBAAc,KAAK,UAAU;AAC7B,WAAK,aAAa;AAAA,IACpB;AACA,SAAK,OAAO,UAAU;AACtB,SAAK,OAAO,MAAM;AAClB,SAAK,OAAO,aAAY,oBAAI,KAAK,GAAE,YAAY;AAC/C,SAAK,MAAM;AAAA,EACb;AAAA;AAAA,EAGA,OAAO,SAAgC;AAErC,QAAI,QAAQ,eAAe;AACzB,WAAK,OAAO,gBAAgB,EAAE,GAAG,KAAK,OAAO,eAAe,GAAG,QAAQ,cAAc;AACrF,aAAO,QAAQ;AAAA,IACjB;AACA,QAAI,QAAQ,eAAe;AACzB,WAAK,OAAO,gBAAgB,EAAE,GAAG,KAAK,OAAO,eAAe,GAAG,QAAQ,cAAc;AACrF,aAAO,QAAQ;AAAA,IACjB;AACA,QAAI,QAAQ,gBAAgB;AAC1B,WAAK,OAAO,iBAAiB,EAAE,GAAG,KAAK,OAAO,gBAAgB,GAAG,QAAQ,eAAe;AACxF,aAAO,QAAQ;AAAA,IACjB;AACA,WAAO,OAAO,KAAK,QAAQ,OAAO;AAAA,EACpC;AAAA;AAAA,EAGA,OAAO,oBAA4B;AACjC,WAAO,KAAK,WAAW,GAAG,WAAW;AAAA,EACvC;AAAA;AAAA,EAGA,OAAO,OAA4B;AACjC,UAAM,WAAW,cAAa,kBAAkB;AAChD,QAAI;AACF,UAAI,WAAW,QAAQ,GAAG;AACxB,eAAO,KAAK,MAAM,aAAa,UAAU,OAAO,CAAC;AAAA,MACnD;AAAA,IACF,QAAQ;AAAA,IAER;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,QAAQ;AACd,SAAK,OAAO,aAAY,oBAAI,KAAK,GAAE,YAAY;AAC/C,QAAI;AACF,oBAAc,KAAK,UAAU,KAAK,UAAU,KAAK,QAAQ,MAAM,CAAC,GAAG,OAAO;AAAA,IAC5E,QAAQ;AAAA,IAER;AAAA,EACF;AACF;","names":[]}
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  ensureDirectory,
4
4
  getDbPath
5
- } from "./chunk-WJKZWKER.js";
5
+ } from "./chunk-63FVALWX.js";
6
6
 
7
7
  // src/core/database.ts
8
8
  import initSqlJs from "sql.js";
@@ -460,4 +460,4 @@ var SkilloDatabase = class {
460
460
  export {
461
461
  SkilloDatabase
462
462
  };
463
- //# sourceMappingURL=chunk-2CVEPT6U.js.map
463
+ //# sourceMappingURL=chunk-73NUWYUO.js.map