@fermindi/pwn-cli 0.3.0 → 0.3.1

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/cli/inject.js CHANGED
@@ -65,7 +65,9 @@ export default async function injectCommand(args = []) {
65
65
  console.log(' ├── patterns/ (auto-applied patterns)');
66
66
  console.log(' ├── workflows/ (batch execution)');
67
67
  console.log(' ├── agents/ (AI agent configs)');
68
- console.log(' └── config/ (notifications, etc)\n');
68
+ console.log(' └── config/ (notifications, etc)');
69
+ console.log(' .claude/');
70
+ console.log(' └── commands/ (slash commands: /save)\n');
69
71
 
70
72
  // Show ntfy topic if generated
71
73
  const notifyPath = join(process.cwd(), '.ai', 'config', 'notifications.json');
package/cli/update.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { existsSync, readFileSync, writeFileSync, cpSync, renameSync } from 'fs';
2
+ import { existsSync, readFileSync, writeFileSync, cpSync, renameSync, mkdirSync, readdirSync } from 'fs';
3
3
  import { join, dirname } from 'path';
4
4
  import { fileURLToPath } from 'url';
5
5
 
@@ -21,6 +21,13 @@ const FRAMEWORK_FILES = [
21
21
  'README.md',
22
22
  ];
23
23
 
24
+ /**
25
+ * Claude Code slash commands (in .claude/commands/)
26
+ */
27
+ const CLAUDE_COMMANDS = [
28
+ 'save.md',
29
+ ];
30
+
24
31
  /**
25
32
  * Files that should NOT be updated (user data)
26
33
  * These contain user customizations
@@ -148,6 +155,39 @@ export default async function updateCommand(args = []) {
148
155
  }
149
156
  }
150
157
 
158
+ // Update .claude/commands/ (slash commands)
159
+ const claudeCommandsDir = join(cwd, '.claude', 'commands');
160
+ const templateCommandsDir = join(__dirname, '../templates/workspace/.claude/commands');
161
+
162
+ if (existsSync(templateCommandsDir)) {
163
+ for (const cmdFile of CLAUDE_COMMANDS) {
164
+ const templateFile = join(templateCommandsDir, cmdFile);
165
+ const targetFile = join(claudeCommandsDir, cmdFile);
166
+
167
+ if (!existsSync(templateFile)) {
168
+ continue;
169
+ }
170
+
171
+ const templateContent = readFileSync(templateFile, 'utf8');
172
+ const targetExists = existsSync(targetFile);
173
+ const targetContent = targetExists ? readFileSync(targetFile, 'utf8') : '';
174
+
175
+ if (templateContent !== targetContent) {
176
+ if (dryRun) {
177
+ console.log(` 📝 Would update: .claude/commands/${cmdFile}`);
178
+ } else {
179
+ // Ensure directory exists
180
+ if (!existsSync(claudeCommandsDir)) {
181
+ mkdirSync(claudeCommandsDir, { recursive: true });
182
+ }
183
+ writeFileSync(targetFile, templateContent);
184
+ console.log(` 📝 Updated: .claude/commands/${cmdFile}`);
185
+ }
186
+ updated.push(`.claude/commands/${cmdFile}`);
187
+ }
188
+ }
189
+ }
190
+
151
191
  // Update state.json with new version
152
192
  if (!dryRun && existsSync(statePath)) {
153
193
  try {
@@ -185,5 +225,6 @@ export default async function updateCommand(args = []) {
185
225
  console.log('🔒 Preserved (user data):');
186
226
  console.log(' .ai/memory/ (decisions, patterns, deadends)');
187
227
  console.log(' .ai/tasks/ (active, backlog)');
188
- console.log(' .ai/state.json (session state)\n');
228
+ console.log(' .ai/state.json (session state)');
229
+ console.log(' .claude/ (your custom commands preserved)\n');
189
230
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fermindi/pwn-cli",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Professional AI Workspace - Inject structured memory and automation into any project for AI-powered development",
5
5
  "type": "module",
6
6
  "bin": {
@@ -86,6 +86,14 @@ export function getTemplatePath() {
86
86
  return join(__dirname, '../../templates/workspace/.ai');
87
87
  }
88
88
 
89
+ /**
90
+ * Get the path to the .claude commands template
91
+ * @returns {string} Path to .claude template directory
92
+ */
93
+ export function getClaudeCommandsTemplatePath() {
94
+ return join(__dirname, '../../templates/workspace/.claude');
95
+ }
96
+
89
97
  /**
90
98
  * Inject PWN workspace into a project
91
99
  * @param {object} options - Injection options
@@ -104,7 +112,9 @@ export async function inject(options = {}) {
104
112
  } = options;
105
113
 
106
114
  const templateDir = getTemplatePath();
115
+ const claudeTemplateDir = getClaudeCommandsTemplatePath();
107
116
  const targetDir = join(cwd, '.ai');
117
+ const claudeDir = join(cwd, '.claude');
108
118
 
109
119
  const log = silent ? () => {} : console.log;
110
120
 
@@ -193,6 +203,24 @@ export async function inject(options = {}) {
193
203
  }
194
204
  }
195
205
 
206
+ // Copy .claude/commands/ for slash commands
207
+ if (existsSync(claudeTemplateDir)) {
208
+ // Create .claude/commands/ if it doesn't exist
209
+ const commandsDir = join(claudeDir, 'commands');
210
+ if (!existsSync(commandsDir)) {
211
+ mkdirSync(commandsDir, { recursive: true });
212
+ }
213
+
214
+ // Copy all command files
215
+ const claudeCommandsSource = join(claudeTemplateDir, 'commands');
216
+ if (existsSync(claudeCommandsSource)) {
217
+ cpSync(claudeCommandsSource, commandsDir, { recursive: true });
218
+ if (!silent) {
219
+ console.log('📝 Created .claude/commands/ with PWN slash commands');
220
+ }
221
+ }
222
+ }
223
+
196
224
  // Backup other AI files (not CLAUDE.md) to .ai/
197
225
  const otherFiles = Object.fromEntries(
198
226
  Object.entries(backedUpContent).filter(([k]) => k.toLowerCase() !== 'claude.md')
@@ -0,0 +1,142 @@
1
+ # /save - PWN Session Save
2
+
3
+ Save your current work state to PWN framework files (.ai/state.json and .ai/memory/).
4
+
5
+ ## What this command does
6
+
7
+ 1. Updates .ai/state.json with current session state
8
+ 2. Updates .ai/tasks/active.md with task progress
9
+ 3. Logs new dead ends to .ai/memory/deadends.md
10
+ 4. Optionally updates .ai/memory/decisions.md with new decisions
11
+ 5. Creates archive entry in .ai/memory/archive/
12
+
13
+ ---
14
+
15
+ ## Instructions
16
+
17
+ First, identify the current developer by running:
18
+
19
+ ```bash
20
+ git config user.name
21
+ ```
22
+
23
+ Then, analyze the current session and update PWN files accordingly.
24
+
25
+ ## Files to Update
26
+
27
+ ### 1. State File (.ai/state.json)
28
+
29
+ Update the session state:
30
+
31
+ ```json
32
+ {
33
+ "developer": "{username from git config}",
34
+ "session_started": "{ISO timestamp}",
35
+ "session_mode": "interactive",
36
+ "current_task": "{task ID or null}",
37
+ "context_loaded": ["memory", "patterns", "tasks"],
38
+ "last_save": "{current ISO timestamp}"
39
+ }
40
+ ```
41
+
42
+ ### 2. Active Tasks (.ai/tasks/active.md)
43
+
44
+ If there are tasks in progress:
45
+ - Update checkbox status ([ ] or [x])
46
+ - Add notes about blockers
47
+ - Update priority if changed
48
+
49
+ ### 3. Dead Ends (.ai/memory/deadends.md)
50
+
51
+ When a new dead end is discovered:
52
+
53
+ 1. **Get next ID** from existing entries (last DE-XXX + 1)
54
+
55
+ 2. **Add detailed entry**:
56
+ ```markdown
57
+ ## DE-XXX: Title
58
+
59
+ **Date:** YYYY-MM-DD
60
+ **Attempted:** What was tried
61
+ **Problem:** Why it failed
62
+ **Solution:** What worked instead
63
+ **Tags:** relevant, keywords
64
+ ```
65
+
66
+ ### 4. Decisions (.ai/memory/decisions.md)
67
+
68
+ If new architectural decisions were made:
69
+
70
+ 1. **Get next ID** from existing entries (last DEC-XXX + 1)
71
+
72
+ 2. **Add entry**:
73
+ ```markdown
74
+ ## DEC-XXX: Decision Title
75
+
76
+ **Date:** YYYY-MM-DD
77
+ **Status:** Active
78
+ **Context:** Why this decision was needed
79
+ **Decision:** What was decided
80
+ **Rationale:** Why this is the best choice
81
+ ```
82
+
83
+ ### 5. Archive Entry (.ai/memory/archive/{date}-session.md)
84
+
85
+ Create a session summary:
86
+
87
+ ```markdown
88
+ # Session: YYYY-MM-DD
89
+
90
+ ## Summary
91
+ {brief description of what was done this session}
92
+
93
+ ## Tasks
94
+ ### Completed
95
+ - [x] Task descriptions...
96
+
97
+ ### In Progress
98
+ - [ ] Task descriptions...
99
+
100
+ ## Decisions Made
101
+ - DEC-XXX: description (if any)
102
+
103
+ ## Dead Ends
104
+ - DE-XXX: description (if any)
105
+
106
+ ---
107
+ *Saved: {ISO timestamp}*
108
+ ```
109
+
110
+ ---
111
+
112
+ ## Output Format
113
+
114
+ After updating all files, confirm to the user:
115
+
116
+ ```
117
+ PWN Save Complete:
118
+ - State: .ai/state.json updated (developer: {username})
119
+ - Tasks: {X} active, {Y} completed
120
+ - Dead Ends: {new count or "no new"}
121
+ - Decisions: {new count or "no new"}
122
+ - Archive: .ai/memory/archive/{filename}
123
+ - Last updated: {timestamp}
124
+ ```
125
+
126
+ ---
127
+
128
+ ## Rules
129
+
130
+ 1. **state.json**: Only current session state, no history
131
+ 2. **deadends.md**: Detailed entries with proper DE-XXX IDs
132
+ 3. **decisions.md**: Organized entries with proper DEC-XXX IDs
133
+ 4. **active.md**: Only current sprint tasks
134
+ 5. **archive/**: One file per session with summary
135
+
136
+ ---
137
+
138
+ ## Notes
139
+
140
+ - This command replaces the old /checkpoint command
141
+ - Uses PWN framework structure in .ai/ directory
142
+ - Always get the next available ID number before adding entries